Просмотр исходного кода

add support uffs interface

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1243 bbd45198-f89e-11dd-88c7-29a3b14d5316
iamyhw@gmail.com 15 лет назад
Родитель
Сommit
0030a2d396
47 измененных файлов с 12418 добавлено и 12891 удалено
  1. 307 62
      components/dfs/filesystems/uffs/dfs_uffs.c
  2. 22 12
      components/dfs/filesystems/uffs/dfs_uffs.h
  3. 1 1
      components/dfs/filesystems/uffs/src/emu/cmdline.h
  4. 2 2
      components/dfs/filesystems/uffs/src/emu/uffs_os_posix.c
  5. 12 12
      components/dfs/filesystems/uffs/src/example/CMakeLists.txt
  6. 402 310
      components/dfs/filesystems/uffs/src/example/flash-interface-example.c
  7. 155 161
      components/dfs/filesystems/uffs/src/example/static-mem-allocate.c
  8. 109 109
      components/dfs/filesystems/uffs/src/inc/uffs/uffs.h
  9. 70 70
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_badblock.h
  10. 107 107
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_blockinfo.h
  11. 174 174
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_buf.h
  12. 277 277
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_config.h
  13. 59 59
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_core.h
  14. 191 191
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_device.h
  15. 90 90
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_ecc.h
  16. 152 150
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_fd.h
  17. 74 74
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_find.h
  18. 274 274
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_flash.h
  19. 137 137
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_fs.h
  20. 130 130
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_mem.h
  21. 90 90
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_mtb.h
  22. 65 65
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_os.h
  23. 92 92
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_pool.h
  24. 243 243
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_public.h
  25. 221 221
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_tree.h
  26. 158 156
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_types.h
  27. 85 85
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_utils.h
  28. 54 54
      components/dfs/filesystems/uffs/src/inc/uffs/uffs_version.h
  29. 49 49
      components/dfs/filesystems/uffs/src/uffs/CMakeLists.txt
  30. 188 188
      components/dfs/filesystems/uffs/src/uffs/uffs_badblock.c
  31. 302 302
      components/dfs/filesystems/uffs/src/uffs/uffs_blockinfo.c
  32. 1591 1591
      components/dfs/filesystems/uffs/src/uffs/uffs_buf.c
  33. 144 144
      components/dfs/filesystems/uffs/src/uffs/uffs_debug.c
  34. 94 94
      components/dfs/filesystems/uffs/src/uffs/uffs_device.c
  35. 357 357
      components/dfs/filesystems/uffs/src/uffs/uffs_ecc.c
  36. 531 532
      components/dfs/filesystems/uffs/src/uffs/uffs_fd.c
  37. 372 360
      components/dfs/filesystems/uffs/src/uffs/uffs_find.c
  38. 674 674
      components/dfs/filesystems/uffs/src/uffs/uffs_flash.c
  39. 1644 1627
      components/dfs/filesystems/uffs/src/uffs/uffs_fs.c
  40. 144 144
      components/dfs/filesystems/uffs/src/uffs/uffs_init.c
  41. 16 872
      components/dfs/filesystems/uffs/src/uffs/uffs_mem.c
  42. 250 247
      components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c
  43. 343 343
      components/dfs/filesystems/uffs/src/uffs/uffs_pool.c
  44. 533 533
      components/dfs/filesystems/uffs/src/uffs/uffs_public.c
  45. 1171 1164
      components/dfs/filesystems/uffs/src/uffs/uffs_tree.c
  46. 195 195
      components/dfs/filesystems/uffs/src/uffs/uffs_utils.c
  47. 67 67
      components/dfs/filesystems/uffs/src/uffs/uffs_version.c

+ 307 - 62
components/dfs/filesystems/uffs/dfs_uffs.c

@@ -1,92 +1,337 @@
-#include <rtthread.h>
-#include <dfs.h>
+#include <rtthread.h>   
+#include <dfs_def.h>   
 #include <dfs_fs.h>
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_fd.h"
+#include "uffs_ext.h"
 
-/* mount and unmount file system */
-static int dfs_uffs_mount(struct dfs_filesystem* fs, unsigned long rwflag, const void* data)
+/* mount and unmount file system */ 
+int dfs_uffs_mount(struct dfs_filesystem* fs, unsigned long rwflag, const void* data)   
 {
-}
+	return ((uffs_InitMountTable() == U_SUCC) ? 0 : -1);   
+}      
 
-static int dfs_uffs_unmount(struct dfs_filesystem* fs)
+int dfs_uffs_unmount(struct dfs_filesystem* fs)   
 {
-}
+	uffs_ReleaseObjectBuf();
+	return uffs_ReleaseMountTable();  
+}      
 
-static int dfs_uffs_mkfs(const char* device_name)
-{
-	return -DFS_STATUS_EIO;
-}
+int dfs_uffs_mkfs(const char* device_name)   
+{        
+	return uffs_format(NULL);   
+}      
 
-static int dfs_uffs_statfs(struct dfs_filesystem* fs, struct _statfs *buf)
+int dfs_uffs_statfs(struct dfs_filesystem* fs, struct statfs *buf)   
 {
-}
+	int ret = U_SUCC;
+	uffs_MountTable *entry = (uffs_MountTable*)(fs->dev_id->user_data);
+	struct uffs_StorageAttrSt *attr = entry->dev->attr;
 
-static int dfs_uffs_open(struct dfs_fd* fd)
-{
-}
+	buf->f_bsize  = attr->page_data_size * attr->pages_per_block;
+	buf->f_blocks = attr->total_blocks;
+	buf->f_bfree  = 0;
 
-static int dfs_uffs_close(struct dfs_fd* fd)
-{
-}
+	return ret;   
+}      
 
-static int dfs_uffs_ioctl(struct dfs_fd* fd, int cmd, void *args)
-{
-}
+int dfs_uffs_open(struct dfs_fd* fd)   
+{	
+	int ret=U_SUCC;
+
+	if (fd->flags & DFS_O_DIRECTORY)
+	{//Îļþ¼Ð
+		uffs_DIR *dirp;
+		/* open directory */
+		
+		if (fd->flags & DFS_O_CREAT)
+		{//´´½¨
+			ret = uffs_open(fd->path,UO_CREATE|UO_DIR);
+			if(ret != U_SUCC)
+			{
+				return U_FAIL;
+			}
+		}
+
+		dirp = uffs_opendir(fd->path);
+		if(dirp == NULL) 
+		{
+			uffs_set_error(-UEMFILE);
+			ret = U_FAIL;
+		}
+
+		fd->data = dirp;
+
+		return U_SUCC;
+	}
+	else
+	{//Îļþ
+		uffs_Object *fp;
+		
+		int mode = UO_RDONLY;
+
+		if (fd->flags & DFS_O_WRONLY) mode |= UO_WRONLY;
+		if ((fd->flags & DFS_O_ACCMODE) & DFS_O_RDWR) mode |= UO_WRONLY;
+		/* Opens the file, if it is existing. If not, a new file is created. */
+		if (fd->flags & DFS_O_CREAT) mode |= UO_CREATE;
+		/* Creates a new file. If the file is existing, it is truncated and overwritten. */
+		if (fd->flags & DFS_O_TRUNC) mode |= UO_TRUNC;
+		/* Creates a new file. The function fails if the file is already existing. */
+		if (fd->flags & DFS_O_EXCL) mode |= UO_EXCL;
+
+		/* allocate a fd */
+		
+		/* open directory */
+		fp = uffs_GetObject();
+		if(fp == NULL) 
+		{
+			uffs_set_error(-UEMFILE);
+			ret = U_FAIL;
+		}
+
+		if(uffs_OpenObject(fp, fd->path, mode) == RT_EOK)
+		{
+			struct uffs_stat stat_buf;
+
+			uffs_stat(fd->path, &stat_buf);
+
+			fd->pos  = fp->pos;
+			fd->size = stat_buf.st_size;
+			fd->data = fp;
+
+			if(fd->flags & DFS_O_APPEND)
+			{
+				fd->pos = uffs_SeekObject(fp, 0, USEEK_END);
+			}
+			ret = U_SUCC;
+		}
+		else
+		{
+			/* open failed, return */
+			uffs_set_error(-uffs_GetObjectErr(fp));
+			uffs_PutObject(fp);
+			return U_FAIL;
+		}
+	}
 
-static int dfs_uffs_read(struct dfs_fd* fd, void* buf, rt_size_t count)
+	return ret;  
+}      
+
+int dfs_uffs_close(struct dfs_fd* fd)   
 {
-}
+	int ret=U_SUCC;
+
+	if (fd->type == FT_DIRECTORY)
+	{
+		uffs_DIR* dirp;
+
+		dirp = (uffs_DIR*)(fd->data);
+		RT_ASSERT(dirp != RT_NULL);
+
+		uffs_closedir(dirp);
+	}
+	else if (fd->type == FT_REGULAR)
+	{
+		uffs_Object* fp;
+
+		fp = (uffs_Object*)(fd->data);
+
+		RT_ASSERT(fd != RT_NULL);
+
+		ret = uffs_CloseObject(fp);
+		uffs_PutObject(fp);
+	}
 
-static int dfs_uffs_write(struct dfs_fd* fd, const void* buf, rt_size_t count)
+	return ret;   
+}      
+
+int dfs_uffs_ioctl(struct dfs_fd* fd, int cmd, void *args)   
 {
-}
+	return -DFS_STATUS_ENOSYS;   
+}      
 
-static int dfs_uffs_flush(struct dfs_fd* fd)
+int dfs_uffs_read(struct dfs_fd* fd, void* buf, rt_size_t count)   
 {
-}
+	uffs_Object* fp;
+	uffs_DIR* dirp;
+
+	if (fd->type == FT_DIRECTORY)
+	{
+		dirp = (uffs_DIR*)(fd->data);
+		fp = dirp->obj;
+	}
+	else
+	{
+		fp = (uffs_Object*)(fd->data);
+	}
+
+	RT_ASSERT(fd != RT_NULL);
+
+	/* update position */
+	fd->pos  = fp->pos;
 
-static int dfs_uffs_lseek(struct dfs_fd* fd, rt_off_t offset)
+	return uffs_ReadObject(fp, buf, count);  
+}      
+
+int dfs_uffs_write(struct dfs_fd* fd, const void* buf, rt_size_t count)   
 {
-}
+	uffs_Object* fp;
+	u32 byte_write;
+	struct uffs_stat stat_buf;
+
+	if(fd->type == FT_DIRECTORY)
+	{
+		return -DFS_STATUS_EISDIR;
+	}
+
+	fp = (uffs_Object*)(fd->data);
+	RT_ASSERT(fp != RT_NULL);
 
-static int dfs_uffs_getdents(struct dfs_fd* fd, struct _dirent* dirp, rt_uint32_t count)
+	byte_write = uffs_WriteObject(fp, buf, count);
+
+	/* update position and file size */
+	fd->pos  = fp->pos;
+
+	uffs_stat(fp->name, &stat_buf);
+	fd->size = stat_buf.st_size;
+
+	return byte_write;   
+}      
+
+int dfs_uffs_flush(struct dfs_fd* fd)   
 {
-}
+	uffs_Object* fp;
 
-static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* pathname)
+	fp = (uffs_Object*)(fd->data);
+	RT_ASSERT(fp != RT_NULL);
+
+	return uffs_FlushObject(fp); 
+}      
+
+int dfs_uffs_lseek(struct dfs_fd* fd, rt_off_t offset)   
 {
-}
+	uffs_Object* fp;
+
+	fp = (uffs_Object*)(fd->data);
+	RT_ASSERT(fp != RT_NULL);
 
-static int dfs_uffs_stat(struct dfs_filesystem* fs, const char* filename, struct _stat* buf)
+	return uffs_SeekObject(fp, USEEK_SET, offset);
+}      
+
+int dfs_uffs_getdents(struct dfs_fd* fd, struct dirent* dir, rt_uint32_t count)   
 {
-}
+	uffs_DIR* dirp;
+	struct uffs_dirent *ent;
+	rt_uint32_t index;
+	struct dirent* d;
+
+	dirp = (uffs_DIR*)(fd->data);
+	RT_ASSERT(dirp != RT_NULL);
+
+	/* make integer count */
+	count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
+	if ( count == 0 ) return -DFS_STATUS_EINVAL;
+
+	index = 0;
+	while (1)
+	{
+		d = dir + index;
+
+		ent = uffs_readdir(dirp);
+		if(ent == RT_NULL)break;
+
+
+		d->d_type = DFS_DT_DIR;
 
-static int dfs_uffs_rename(struct dfs_filesystem* fs, const char* oldpath, const char* newpath)
+		d->d_namlen = ent->d_namelen;
+		d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
+		rt_strncpy(d->d_name, ent->d_name, rt_strlen(ent->d_name) + 1);
+
+		index ++;
+		if ( index * sizeof(struct dirent) >= count )
+			break;
+	}
+	return index * sizeof(struct dirent);
+}      
+
+//Delete a File or Directory
+int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* path)   
 {
-}
+	int ret;
+	int err = 0;
+
+	ret = uffs_DeleteObject(path, &err);
+	uffs_set_error(-err);
+
+	return ret;   
+}      
 
-static const struct dfs_filesystem_operation _uffs = 
+int dfs_uffs_stat(struct dfs_filesystem* fs, const char* path, struct stat* st)   
 {
-	"uffs",
-	dfs_uffs_mount,
-	dfs_uffs_unmount,
-	dfs_uffs_mkfs,
-	dfs_uffs_statfs,
-
-	dfs_uffs_open,
-	dfs_uffs_close,
-	dfs_uffs_ioctl,
-	dfs_uffs_read,
-	dfs_uffs_write,
-	dfs_uffs_flush,
-	dfs_uffs_lseek,
-	dfs_uffs_getdents,
-	dfs_uffs_unlink,
-	dfs_uffs_stat,
-	dfs_uffs_rename,
-};
-
-int dfs_uffs_init(void)
+	int ret=U_SUCC;
+	struct uffs_stat stat_buf;
+
+	ret = uffs_stat(path, &stat_buf);
+
+	if (ret == U_SUCC)
+	{
+		st->st_dev = 0;
+		//st->st_mode = stat_buf.st_mode;
+		
+		st->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
+		DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
+		if (stat_buf.st_mode & US_IFDIR)
+		{
+			st->st_mode &= ~DFS_S_IFREG;
+			st->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
+		}
+		if (stat_buf.st_mode & US_IREAD)
+			st->st_mode &= ~(DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH);
+		st->st_size = stat_buf.st_size;
+		st->st_mtime= stat_buf.st_mtime;
+		st->st_blksize= stat_buf.st_blksize;
+
+		return U_SUCC;
+	}
+
+	return U_FAIL;
+}      
+
+int dfs_uffs_rename(struct dfs_filesystem* fs, const char* oldpath, const char* newpath)   
 {
-    /* register UFFS file system */
-    return dfs_register(&_uffs);
-}
+	int ret;
+	int err = 0;
+
+	ret = uffs_RenameObject(oldpath, newpath, &err);
+	uffs_set_error(-err);
+
+	return ret;  
+}      
+
+struct dfs_filesystem_operation _uffs =    
+{           
+	"uffs",           
+	dfs_uffs_mount,           
+	dfs_uffs_unmount,           
+	dfs_uffs_mkfs,           
+	dfs_uffs_statfs,              
+	dfs_uffs_open,           
+	dfs_uffs_close,           
+	dfs_uffs_ioctl,           
+	dfs_uffs_read,           
+	dfs_uffs_write,           
+	dfs_uffs_flush,           
+	dfs_uffs_lseek,           
+	dfs_uffs_getdents,           
+	dfs_uffs_unlink,           
+	dfs_uffs_stat,           
+	dfs_uffs_rename,   
+};      
+
+int dfs_uffs_init(void)   
+{       
+	/* register UFFS file system */       
+	return dfs_register(&_uffs);   
+} 
+

+ 22 - 12
components/dfs/filesystems/uffs/dfs_uffs.h

@@ -1,20 +1,30 @@
 /*
- * File      : dfs_uffs.h
- * This file is part of Device File System in RT-Thread RTOS
- * COPYRIGHT (C) 2004-2010, RT-Thread Development Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2010-09-02     Bernard      The first version.
- */
++------------------------------------------------------------------------------
+| Project   : Device Filesystem
++------------------------------------------------------------------------------
+| Copyright 2010  
+| All rights reserved.
+|------------------------------------------------------------------------------
+| File      : dfs_uffs.h
+|------------------------------------------------------------------------------
+| Chang Logs:
+| Date           Author       Notes
+| 2010-12-24     amsl         Add dfs_uffs_init function declaration
++------------------------------------------------------------------------------
+*/
 
 #ifndef __DFS_UFFS_H__
 #define __DFS_UFFS_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int dfs_uffs_init(void);
 
+#ifdef __cplusplus
+}
 #endif
+
+#endif
+

+ 1 - 1
components/dfs/filesystems/uffs/src/emu/cmdline.h

@@ -57,7 +57,7 @@ struct cli_commandset {
 const char * cli_getparam(const char *tail, const char **next);
 void cli_add_commandset(struct cli_commandset *cmds);
 void cliInterpret(const char *line);
-void cliMain();
+void cliMain(void);
 
 #endif
 

+ 2 - 2
components/dfs/filesystems/uffs/src/emu/uffs_os_posix.c

@@ -37,7 +37,7 @@
  */
 #include "uffs/uffs_os.h"
 #include "uffs/uffs_public.h"
-#include <memory.h>
+//#include <memory.h>
 #include <stdlib.h>
 #include <time.h>
 
@@ -98,7 +98,7 @@ unsigned int uffs_GetCurDateTime(void)
 	//			or just return 0 if you don't care about file time.
 	time_t tvalue;
 
-	tvalue = time(NULL);
+	tvalue = 0;//time(NULL);
 	
 	return (unsigned int)tvalue;
 }

+ 12 - 12
components/dfs/filesystems/uffs/src/example/CMakeLists.txt

@@ -1,12 +1,12 @@
-INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
-INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/emu)
-
-LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/emu)
-LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/uffs)
-
-SET(static_mem_SRCS static-mem-allocate.c)
-SET(flash_if_SRCS flash-interface-example.c)
-ADD_EXECUTABLE(static-mem-example ${static_mem_SRCS})
-ADD_EXECUTABLE(flash-if-example ${flash_if_SRCS})
-TARGET_LINK_LIBRARIES(static-mem-example emu uffs emu)
-TARGET_LINK_LIBRARIES(flash-if-example emu uffs emu)
+INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
+INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/emu)
+
+LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/emu)
+LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/uffs)
+
+SET(static_mem_SRCS static-mem-allocate.c)
+SET(flash_if_SRCS flash-interface-example.c)
+ADD_EXECUTABLE(static-mem-example ${static_mem_SRCS})
+ADD_EXECUTABLE(flash-if-example ${flash_if_SRCS})
+TARGET_LINK_LIBRARIES(static-mem-example emu uffs emu)
+TARGET_LINK_LIBRARIES(flash-if-example emu uffs emu)

+ 402 - 310
components/dfs/filesystems/uffs/src/example/flash-interface-example.c

@@ -1,310 +1,402 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.my_application_main_entry
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-/**
- * \file flash-interface-example.c
- * \brief example for using flash driver and multiple partitions, with static memory allocator.
- * \author Ricky Zheng, created at 27 Nov, 2007
- */
-  
-#include <string.h>
-
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_flash.h"
-#include "uffs/uffs_mtb.h"
-#include "uffs/uffs_fs.h"
-
-#define PFX "nand-drv:"
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
-int main()
-{
-	uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
-	return 0;
-}
-#else
-
-
-#define USE_SINGLE_WRITE_FUN
-
-
-#ifdef USE_SINGLE_WRITE_FUN
-static int nand_write_full_page(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, const u8 *tag, int tag_len, const u8 *ecc);
-#else
-static int nand_write_page_data(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, u8 *ecc);
-static int nand_write_page_spare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len, UBOOL eod);
-#endif
-
-static int nand_read_page_data(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int len, u8 *ecc);
-static int nand_read_page_spare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len);
-
-static int nand_erase_block(uffs_Device *dev, u32 blockNumber);
-
-static URET nand_init_device(uffs_Device *dev);
-
-
-#ifdef USE_SINGLE_WRITE_FUN
-// if you want to optimize nand flash driver, or use special nand hardware controller, 
-// or use other NAND driver (for example, eCos NAND lib), you shoud do layout in nand driver.
-static int nand_write_full_page(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, const u8 *tag, int tag_len, const u8 *ecc)
-{
-#define SPOOL(dev) &((dev)->mem.spare_pool)
-
-	u8 *spare_buf = NULL;
-	
-	spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev));  // alloc a spare buffer
-	
-	// ... START WRITE COMMAND ...
-	// ...
-	
-	if (page) {
-		// WRITE page data
-		// ....		
-		if (dev->attr->ecc_opt == UFFS_ECC_HW) {
-			// read ECC from hardware controller to ecc buf,
-			// ...
-		}
-	}
-	
-	if (tag && tag_len > 0) {
-		
-		// now, you can use UFFS's layout function
-			uffs_FlashMakeSpare(dev, (uffs_TagStore *)tag, ecc, spare_buf);
-		// or, do your own layout
-		//   ....
-		
-		// WRITE spare_buf to page spare ...
-		// ...
-	}
-	
-	// FINISH write command ...
-	// ...
-	// read program status ...
-	// ...
-  
-	if (page)
-		dev->st.page_write_count++;
-	if (tag)
-		dev->st.spare_write_count++;
-	
-	if (spare_buf)
-		uffs_PoolPut(SPOOL(dev), spare_buf);  // release spare buffer
-	
-	return UFFS_FLASH_NO_ERR;
-}
-
-#else
-
-static int nand_write_page_data(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, u8 *ecc)
-{
-	// send WRITE command
-
-	// ... transfer data ...
-	
-	dev->st.page_write_count++;
-	return UFFS_FLASH_NO_ERR;
-}
-
-
-static int nand_write_page_spare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len, UBOOL eod)
-{
-	if (eod == U_FALSE) {
-		// send WRITE command
-	}
-	else {
-		// do not need to send WRITE command if eod == U_FALSE because 'nand_write_page_data' is called before.
-	}
-
-	// ... transfer data ...
-
-	// send COMMIT command
-
-	// read STATUS
-
-	dev->st.spare_write_count++;  
-	return UFFS_FLASH_NO_ERR;
-}
-
-#endif
-
-
-static int nand_read_page_data(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int len, u8 *ecc)
-{
-	// send READ command
-
-	// ... transfer data ...
-
-	// read STATUS
-
-	dev->st.page_read_count++;
-	return UFFS_FLASH_NO_ERR;
-}
-
-static int nand_read_page_spare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len)
-{
-	// send READ command
-
-	// ... transfer data ...
-
-	// read STATUS
-
-	dev->st.spare_read_count++;		
-	return UFFS_FLASH_NO_ERR;
-}
-
-
-static int nand_erase_block(uffs_Device *dev, u32 blockNumber)
-{
-	// insert your nand driver codes here ...
-
-	dev->st.block_erase_count++;
-	return UFFS_FLASH_NO_ERR;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////
-
-static struct uffs_FlashOpsSt my_nand_driver_ops = {
-	nand_read_page_data,    //ReadPageData
-	nand_read_page_spare,   //ReadPageSpare
-	NULL,                   //ReadPageSpareWithLayout
-#ifdef USE_SINGLE_WRITE_FUN
-	NULL,
-	NULL,
-	nand_write_full_page,   //WriteFullPages
-#else
-	nand_write_page_data,   //WritePageData
-	nand_write_page_spare,  //WritePageSpare
-	NULL,
-#endif	
-	NULL,                   //IsBadBlock
-	NULL,                   //MarkBadBlock
-	nand_erase_block,       //EraseBlock
-};
-
-// change these parameters to fit your nand flash specification
-#define MAN_ID          MAN_ID_SAMSUNG  // simulate Samsung's NAND flash
-
-#define TOTAL_BLOCKS    1024
-#define PAGE_DATA_SIZE  512
-#define PAGE_SPARE_SIZE 16
-#define PAGES_PER_BLOCK 32
-#define PAGE_SIZE		(PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
-#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
-
-#define NR_PARTITION	2								/* total partitions */
-#define PAR_1_BLOCKS	100								/* partition 1 */
-#define PAR_2_BLOCKS	(TOTAL_BLOCKS - PAR_1_BLOCKS)	/* partition 2 */
-
-static struct uffs_StorageAttrSt flash_storage = {0};
-
-/* static alloc the memory for each partition */
-
-static int static_buffer_par1[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_1_BLOCKS) / sizeof(int)];
-static int static_buffer_par2[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_2_BLOCKS) / sizeof(int)];;
-
-
-static void setup_flash_storage(struct uffs_StorageAttrSt *attr)
-{
-	memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
-	
-	attr->total_blocks = TOTAL_BLOCKS;			/* total blocks */
-	attr->page_data_size = PAGE_DATA_SIZE;		/* page data size */
-	attr->pages_per_block = PAGES_PER_BLOCK;	/* pages per block */
-	attr->spare_size = PAGE_SPARE_SIZE;		  	/* page spare size */
-	attr->block_status_offs = 4;				/* block status offset is 5th byte in spare */
-	attr->ecc_opt = UFFS_ECC_SOFT;              /* ecc option */
-	attr->layout_opt = UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
-}
-
-
-static URET my_initDevice(uffs_Device *dev)
-{
-	dev->ops = &my_nand_driver_ops;
-    
-	return U_SUCC;
-}
-
-static URET my_releaseDevice(uffs_Device *dev)
-{
-	return U_SUCC;
-}
-
-/* define mount table */
-static uffs_Device demo_device_1 = {0};
-static uffs_Device demo_device_2 = {0};
-
-static uffs_MountTable demo_mount_table[] = {
-	{ &demo_device_1,  0, PAR_1_BLOCKS - 1, "/data/" },
-	{ &demo_device_2,  PAR_1_BLOCKS, PAR_1_BLOCKS + PAR_2_BLOCKS - 1, "/" },
-	{ NULL, 0, 0, NULL }
-};
-
-static int my_init_filesystem(void)
-{
-	uffs_MountTable *mtbl = &(demo_mount_table[0]);
-
-	/* setup nand storage attributes */
-	setup_flash_storage(&flash_storage);
-
-	/* setup memory allocator */
-	uffs_MemSetupStaticAllocator(&demo_device_1.mem, static_buffer_par1, sizeof(static_buffer_par1));
-	uffs_MemSetupStaticAllocator(&demo_device_2.mem, static_buffer_par2, sizeof(static_buffer_par2));
-
-	/* register mount table */
-	while(mtbl->dev) {
-		mtbl->dev->Init = my_initDevice;
-		mtbl->dev->Release = my_releaseDevice;
-		mtbl->dev->attr = &flash_storage;
-		uffs_RegisterMountTable(mtbl);
-		mtbl++;
-	}
-	
-	return uffs_InitMountTable() == U_SUCC ? 0 : -1;
-}
-
-/* application entry */
-int main()
-{
-	my_init_filesystem();
-
-	// ... my application codes ....
-	// read/write/create/delete files ...
-
-	uffs_ReleaseMountTable();
-
-	return 0;
-}
-
-#endif
-
-
-/////////////////////////////////////////////////////////////////////////////////
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.my_application_main_entry
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+/**
+ * \file flash-interface-example.c
+ * \brief example for using flash driver and multiple partitions, with static memory allocator.
+ * \author Ricky Zheng, created at 27 Nov, 2007
+ */
+  
+#include <string.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_flash.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_fs.h"
+
+#define PFX "nand-drv:"
+
+struct my_nand_chip {
+	void *IOR_ADDR;
+	void *IOW_ADDR;
+	UBOOL inited;
+	// ... 
+};
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0		0
+#define NAND_CMD_READ1		1
+#define NAND_CMD_RNDOUT		5
+#define NAND_CMD_PAGEPROG	0x10
+#define NAND_CMD_READOOB	0x50
+#define NAND_CMD_ERASE1		0x60
+#define NAND_CMD_STATUS		0x70
+#define NAND_CMD_STATUS_MULTI	0x71
+#define NAND_CMD_SEQIN		0x80
+#define NAND_CMD_RNDIN		0x85
+#define NAND_CMD_READID		0x90
+#define NAND_CMD_ERASE2		0xd0
+#define NAND_CMD_RESET		0xff
+
+
+/* impelent the following functions for your NAND flash */
+#define CHIP_SET_CLE(chip) {}
+#define CHIP_CLR_CLE(chip) {}
+#define CHIP_SET_ALE(chip) {}
+#define CHIP_CLR_ALE(chip) {}
+#define CHIP_SET_NCS(chip) {}
+#define CHIP_CLR_NCS(chip) {}
+#define CHIP_BUSY(chip) {}
+#define CHIP_READY(chip) {}
+#define WRITE_COMMAND(chip, cmd) {}
+#define WRITE_DATA_ADDR(chip, block, page, offset) {}
+#define WRITE_ERASE_ADDR(chip, block) {}
+#define WRITE_DATA(chip, data, len) {}
+#define READ_DATA(chip, data, len) {}
+
+#define PARSE_STATUS(v) (UFFS_FLASH_NO_ERR)	// parse status to UFFS_FLASH_NO_ERR or UFFS_FLASH_BAD_BLK
+
+
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
+int main()
+{
+	uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
+	return 0;
+}
+#else
+
+
+static int nand_read_page(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
+						u8 *spare, int spare_len)
+{
+	u8 val = 0;
+	int ret = UFFS_FLASH_NO_ERR;
+	struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private;
+
+	CHIP_CLR_NCS(chip);
+	if (data && data_len > 0) {
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_READ0);
+		CHIP_CLR_CLE(chip);
+		CHIP_SET_ALE(chip);
+		WRITE_DATA_ADDR(chip, block, page, 0);
+		CHIP_CLR_ALE(chip);
+		READ_DATA(chip, data, data_len);
+
+		// for now, we return all 0xFF to pass UFFS mount, you should remove this at your driver
+		memset(data, 0xFF, data_len);
+	}
+
+	if (spare && spare_len > 0) {
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_READOOB);
+		CHIP_CLR_CLE(chip);
+		CHIP_SET_ALE(chip);
+		WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size);
+		CHIP_CLR_ALE(chip);
+		READ_DATA(chip, spare, spare_len);
+
+		// for now, we return all 0xFF to pass UFFS mount, you should remove this at your driver
+		memset(spare, 0xFF, spare_len);
+	}
+
+	if (data == NULL && spare == NULL) {
+		// read bad block mark
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_READOOB);
+		CHIP_CLR_CLE(chip);
+		CHIP_SET_ALE(chip);
+		WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size + attr->block_status_offs);
+		CHIP_CLR_ALE(chip);
+		READ_DATA(chip, &val, 1);
+		ret = (val == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK);
+
+		// for now, we return UFFS_FLASH_NO_ERR to pass UFFS mount, you should remove this at your driver
+		ret = UFFS_FLASH_NO_ERR;
+	}
+
+	CHIP_SET_NCS(chip);
+
+	return ret;
+}
+
+static int nand_write_page(uffs_Device *dev, u32 block, u32 page,
+							const u8 *data, int data_len, const u8 *spare, int spare_len)
+{
+	u8 val = 0;
+	int ret = UFFS_FLASH_NO_ERR;
+	UBOOL fall_through = FALSE;
+	struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private;
+
+	CHIP_CLR_NCS(chip);
+
+	if (data && data_len > 0) {
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_READ0);
+		WRITE_COMMAND(chip, NAND_CMD_SEQIN);
+		CHIP_CLR_CLE(chip);
+		CHIP_SET_ALE(chip);
+		WRITE_DATA_ADDR(chip, block, page, 0);
+		CHIP_CLR_ALE(chip);
+		CHIP_BUSY(chip);
+		WRITE_DATA(chip, data, data_len);
+		if (data_len == dev->attr->page_data_size)
+			fall_through = U_TRUE;
+		else {
+			CHIP_SET_CLE(chip);
+			WRITE_COMMAND(chip, NAND_CMD_PAGEPROG);
+			WRITE_COMMAND(chip, NAND_CMD_STATUS);
+			CHIP_CLR_CLE(chip);
+			CHIP_READY(chip);
+			READ_DATA(chip, &val, 1);
+			ret = PARSE_STATUS(val);
+		}
+	}
+
+	if (ret != UFFS_FLASH_NO_ERR)
+		goto ext;
+
+	if (spare && spare_len > 0) {
+		if (!fall_through) {
+			CHIP_SET_CLE(chip);
+			WRITE_COMMAND(chip, NAND_CMD_READOOB);
+			WRITE_COMMAND(chip, NAND_CMD_SEQIN);
+			CHIP_CLR_CLE(chip);
+			CHIP_SET_ALE(chip);
+			WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size);
+			CHIP_CLR_ALE(chip);
+			CHIP_BUSY(chip);
+		}
+		WRITE_DATA(chip, spare, spare_len);
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_PAGEPROG);
+		WRITE_COMMAND(chip, NAND_CMD_STATUS);
+		CHIP_CLR_CLE(chip);
+		CHIP_READY(chip);
+		READ_DATA(chip, &val, 1);
+		ret = PARSE_STATUS(val);
+	}
+
+	if (data == NULL && spare == NULL) {
+		// mark bad block
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_READOOB);
+		WRITE_COMMAND(chip, NAND_CMD_SEQIN);
+		CHIP_CLR_CLE(chip);
+		CHIP_SET_ALE(chip);
+		WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size + attr->block_status_offs);
+		CHIP_CLR_ALE(chip);
+		CHIP_BUSY(chip);
+		val = 0;
+		WRITE_DATA(chip, &val, 1);
+		CHIP_SET_CLE(chip);
+		WRITE_COMMAND(chip, NAND_CMD_PAGEPROG);
+		WRITE_COMMAND(chip, NAND_CMD_STATUS);
+		CHIP_CLR_CLE(chip);
+		CHIP_READY(chip);
+		READ_DATA(chip, &val, 1);
+		ret = PARSE_STATUS(val);
+	}
+
+ext:
+	CHIP_SET_NCS(chip);
+
+	return ret;
+}
+
+static int nand_erase_block(uffs_Device *dev, u32 block)
+{
+	u8 val;
+	struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private;
+
+	CHIP_CLR_NCS(chip);
+
+	CHIP_SET_CLE(chip);
+	WRITE_COMMAND(chip, NAND_CMD_ERASE1);
+	CHIP_CLR_CLE(chip);
+	CHIP_SET_ALE(chip);
+	WRITE_ERASE_ADDR(chip, blcok);
+	CHIP_CLR_ALE(chip);
+	CHIP_SET_CLE(chip);
+	WRITE_COMMAND(chip, NAND_CMD_ERASE2);
+	WRITE_COMMAND(chip, NAND_CMD_STATUS);
+	CHIP_CLR_CLE(chip);
+	CHIP_READY(chip);
+	READ_DATA(chip, &val, 1);
+
+	CHIP_SET_NCS(chip);
+
+	return PARSE_STATUS(val);
+}
+
+
+static int nand_init_flash(uffs_Device *dev)
+{
+	// initialize your hardware here ...
+	struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private;
+
+	if (!chip->inited) {
+		// setup chip I/O address, setup NAND flash controller ... etc.
+		// chip->IOR_ADDR = 0xF0000000
+		// chip->IOW_ADDR = 0xF0000000
+		chip->inited = U_TRUE;
+	}
+	return 0;
+}
+
+static int nand_release_flash(uffs_Device *dev)
+{
+	// release your hardware here
+	struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private;
+
+	return 0;
+}
+
+static uffs_FlashOps g_my_nand_ops = {
+	nand_init_flash,	// InitFlash()
+	nand_release_flash,	// ReleaseFlash()
+	nand_read_page,		// ReadPage()
+	NULL,				// ReadPageWithLayout
+	nand_write_page,	// WritePage()
+	NULL,				// WirtePageWithLayout
+	NULL,				// IsBadBlock(), let UFFS take care of it.
+	NULL,				// MarkBadBlock(), let UFFS take care of it.
+	nand_erase_block,	// EraseBlock()
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+// change these parameters to fit your nand flash specification
+
+#define TOTAL_BLOCKS    1024
+#define PAGE_DATA_SIZE  512
+#define PAGE_SPARE_SIZE 16
+#define PAGES_PER_BLOCK 32
+#define PAGE_SIZE		(PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
+#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
+
+#define NR_PARTITION	2								/* total partitions */
+#define PAR_1_BLOCKS	100								/* partition 1 */
+#define PAR_2_BLOCKS	(TOTAL_BLOCKS - PAR_1_BLOCKS)	/* partition 2 */
+
+struct my_nand_chip g_nand_chip = {0};
+static struct uffs_StorageAttrSt g_my_flash_storage = {0};
+
+/* define mount table */
+static uffs_Device demo_device_1 = {0};
+static uffs_Device demo_device_2 = {0};
+
+static uffs_MountTable demo_mount_table[] = {
+	{ &demo_device_1,  0, PAR_1_BLOCKS - 1, "/data/" },
+	{ &demo_device_2,  PAR_1_BLOCKS, PAR_1_BLOCKS + PAR_2_BLOCKS - 1, "/" },
+	{ NULL, 0, 0, NULL }
+};
+
+/* static alloc the memory for each partition */
+static int static_buffer_par1[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_1_BLOCKS) / sizeof(int)];
+static int static_buffer_par2[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_2_BLOCKS) / sizeof(int)];;
+
+static void init_nand_chip(struct my_nand_chip *chip)
+{
+	// init chip IO address, etc.
+}
+
+static void setup_flash_storage(struct uffs_StorageAttrSt *attr)
+{
+	memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
+	
+	attr->total_blocks = TOTAL_BLOCKS;			/* total blocks */
+	attr->page_data_size = PAGE_DATA_SIZE;		/* page data size */
+	attr->pages_per_block = PAGES_PER_BLOCK;	/* pages per block */
+	attr->spare_size = PAGE_SPARE_SIZE;		  	/* page spare size */
+	attr->block_status_offs = 4;				/* block status offset is 5th byte in spare */
+	attr->ecc_opt = UFFS_ECC_SOFT;              /* ecc option */
+	attr->layout_opt = UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
+}
+
+static URET my_InitDevice(uffs_Device *dev)
+{
+	dev->attr = &g_my_flash_storage;
+	dev->attr->_private = (void *) &g_nand_chip;	// hook nand_chip data structure to attr->_private
+	dev->ops = &g_my_nand_ops;
+    
+	return U_SUCC;
+}
+
+static URET my_ReleaseDevice(uffs_Device *dev)
+{
+	return U_SUCC;
+}
+
+
+static int my_init_filesystem(void)
+{
+	uffs_MountTable *mtbl = &(demo_mount_table[0]);
+
+	/* setup nand storage attributes */
+	setup_flash_storage(&g_my_flash_storage);
+
+	/* setup memory allocator */
+	uffs_MemSetupStaticAllocator(&demo_device_1.mem, static_buffer_par1, sizeof(static_buffer_par1));
+	uffs_MemSetupStaticAllocator(&demo_device_2.mem, static_buffer_par2, sizeof(static_buffer_par2));
+
+	/* register mount table */
+	while(mtbl->dev) {
+		// setup device init/release entry
+		mtbl->dev->Init = my_InitDevice;
+		mtbl->dev->Release = my_ReleaseDevice;
+		uffs_RegisterMountTable(mtbl);
+		mtbl++;
+	}
+	
+	return uffs_InitMountTable() == U_SUCC ? 0 : -1;
+}
+
+/* application entry */
+int main()
+{
+	my_init_filesystem();
+
+	// ... my application codes ....
+	// read/write/create/delete files ...
+
+	uffs_ReleaseMountTable();
+
+	return 0;
+}
+
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////////

+ 155 - 161
components/dfs/filesystems/uffs/src/example/static-mem-allocate.c

@@ -1,161 +1,155 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file static-mem-allocate.c
- * \brief demostrate how to use static memory allocation. This example use 
- *        file emulated NAND flash.
- * \author Ricky Zheng
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_utils.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs_mtb.h"
-#include "cmdline.h"
-#include "uffs_fileem.h"
-
-#define PFX "static-example: "
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
-int main()
-{
-	uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
-	return 0;
-}
-#else
-
-extern struct cli_commandset * get_helper_cmds(void);
-
-#define DEFAULT_EMU_FILENAME "uffsemfile.bin"
-
-#define PAGE_DATA_SIZE    512
-#define PAGE_SPARE_SIZE   16
-#define PAGES_PER_BLOCK   32
-#define TOTAL_BLOCKS      128
-
-#define PAGE_SIZE					(PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
-#define BLOCK_DATA_SIZE				(PAGES_PER_BLOCK * PAGE_DATA_SIZE)
-#define TOTAL_DATA_SIZE				(TOTAL_BLOCKS * BLOCK_DATA_SIZE)
-#define BLOCK_SIZE					(PAGES_PER_BLOCK * PAGE_SIZE)
-#define TOTAL_SIZE					(BLOCK_SIZE * TOTAL_BLOCKS)
-
-#define MAX_MOUNT_TABLES		10
-#define MAX_MOUNT_POINT_NAME	32
-
-static uffs_Device demo_device = {0};
-static struct uffs_MountTableEntrySt demo_mount = {
-	&demo_device,
-	0,    /* start from block 0 */
-	-1,   /* use whole chip */
-	"/",  /* mount point */
-	NULL
-};
-
-static struct uffs_StorageAttrSt emu_storage = {0};
-static struct uffs_FileEmuSt emu_private = {0};
-
-/* static alloc the memory */
-static int static_buffer_pool[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, TOTAL_BLOCKS) / sizeof(int)];
-
-
-static void setup_emu_storage(struct uffs_StorageAttrSt *attr)
-{
-	attr->total_blocks = TOTAL_BLOCKS;			/* total blocks */
-	attr->page_data_size = PAGE_DATA_SIZE;		/* page data size */
-	attr->spare_size = PAGE_SPARE_SIZE;		  	/* page spare size */
-	attr->pages_per_block = PAGES_PER_BLOCK;	/* pages per block */
-	attr->block_status_offs = 4;				/* block status offset is 5th byte in spare */
-    attr->ecc_opt = UFFS_ECC_SOFT;              /* ecc option */
-    attr->layout_opt = UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
-
-}
-
-static void setup_emu_private(uffs_FileEmu *emu)
-{
-	memset(emu, 0, sizeof(uffs_FileEmu));
-	emu->emu_filename = DEFAULT_EMU_FILENAME;
-}
-
-static int init_uffs_fs(void)
-{
-	struct uffs_MountTableEntrySt *mtbl = &demo_mount;
-
-	/* setup emu storage */
-	setup_emu_storage(&emu_storage);
-	setup_emu_private(&emu_private);
-	emu_storage._private = &emu_private;
-	mtbl->dev->attr = &emu_storage;
-
-	/* setup memory allocator */
-	uffs_MemSetupStaticAllocator(&mtbl->dev->mem, static_buffer_pool, sizeof(static_buffer_pool));
-
-	/* setup device */
-	uffs_fileem_setup_device(mtbl->dev);
-
-	/* register mount table */
-	uffs_RegisterMountTable(mtbl);
-
-	return uffs_InitMountTable() == U_SUCC ? 0 : -1;
-}
-
-static int release_uffs_fs(void)
-{
-	return uffs_ReleaseMountTable();
-}
-
-int main(int argc, char *argv[])
-{
-	int ret;
-
-	ret = init_uffs_fs();
-
-	if (ret != 0) {
-		printf ("Init file system fail: %d\n", ret);
-		return -1;
-	}
-
-	cli_add_commandset(get_helper_cmds());
-	cliMain();
-
-	release_uffs_fs();
-
-	return 0;
-}
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file static-mem-allocate.c
+ * \brief demostrate how to use static memory allocation. This example use 
+ *        file emulated NAND flash, one partition only.
+ * \author Ricky Zheng
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_utils.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_mtb.h"
+#include "cmdline.h"
+#include "uffs_fileem.h"
+
+#define PFX "static-example: "
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
+int main()
+{
+	uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
+	return 0;
+}
+#else
+
+extern struct cli_commandset * get_helper_cmds(void);
+
+#define PAGE_DATA_SIZE    512
+#define PAGE_SPARE_SIZE   16
+#define PAGES_PER_BLOCK   32
+#define TOTAL_BLOCKS      128
+
+#define PAGE_SIZE					(PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
+#define BLOCK_DATA_SIZE				(PAGES_PER_BLOCK * PAGE_DATA_SIZE)
+#define TOTAL_DATA_SIZE				(TOTAL_BLOCKS * BLOCK_DATA_SIZE)
+#define BLOCK_SIZE					(PAGES_PER_BLOCK * PAGE_SIZE)
+#define TOTAL_SIZE					(BLOCK_SIZE * TOTAL_BLOCKS)
+
+#define MAX_MOUNT_TABLES		10
+#define MAX_MOUNT_POINT_NAME	32
+
+static uffs_Device demo_device = {0};
+static struct uffs_MountTableEntrySt demo_mount = {
+	&demo_device,
+	0,    /* start from block 0 */
+	-1,   /* use whole chip */
+	"/",  /* mount point */
+	NULL
+};
+
+/* static alloc the memory */
+static int static_buffer_pool[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, TOTAL_BLOCKS) / sizeof(int)];
+
+
+static void setup_storage(struct uffs_StorageAttrSt *attr)
+{
+	attr->total_blocks = TOTAL_BLOCKS;			/* total blocks */
+	attr->page_data_size = PAGE_DATA_SIZE;		/* page data size */
+	attr->spare_size = PAGE_SPARE_SIZE;		  	/* page spare size */
+	attr->pages_per_block = PAGES_PER_BLOCK;	/* pages per block */
+	attr->block_status_offs = 4;				/* block status offset is 5th byte in spare */
+    attr->ecc_opt = UFFS_ECC_SOFT;              /* use UFFS software ecc */
+    attr->layout_opt = UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
+}
+
+static void setup_device(uffs_Device *dev)
+{
+	// using file emulator device
+	dev->Init = femu_InitDevice;
+	dev->Release = femu_ReleaseDevice;
+	dev->attr = femu_GetStorage();
+}
+
+static int init_uffs_fs(void)
+{
+	struct uffs_MountTableEntrySt *mtbl = &demo_mount;
+
+	/* setup flash storage attributes */
+	setup_storage(femu_GetStorage());
+
+	/* setup memory allocator */
+	uffs_MemSetupStaticAllocator(&mtbl->dev->mem, static_buffer_pool, sizeof(static_buffer_pool));
+
+	/* setup device: init, release, attr */
+	setup_device(mtbl->dev);
+
+	/* register mount table */
+	uffs_RegisterMountTable(mtbl);
+
+	return uffs_InitMountTable() == U_SUCC ? 0 : -1;
+}
+
+static int release_uffs_fs(void)
+{
+	return uffs_ReleaseMountTable();
+}
+
+int main(int argc, char *argv[])
+{
+	int ret;
+
+	ret = init_uffs_fs();
+
+	if (ret != 0) {
+		printf ("Init file system fail: %d\n", ret);
+		return -1;
+	}
+
+	cli_add_commandset(get_helper_cmds());
+	cli_add_commandset(get_test_cmds());
+	cliMain();
+
+	release_uffs_fs();
+
+	return 0;
+}
+
+#endif
+

+ 109 - 109
components/dfs/filesystems/uffs/src/inc/uffs/uffs.h

@@ -1,33 +1,33 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
 */
 /** 
  * \file uffs.h
@@ -37,98 +37,98 @@
 
 #ifndef _UFFS_H_
 #define _UFFS_H_
-
+#include <dfs_def.h>
 #include "uffs/uffs_types.h"
 
 #ifdef __cplusplus
 extern "C"{
-#endif
+#endif
 
-#define UO_RDONLY		0x0000		/** read only */
-#define UO_WRONLY		0x0001		/** write only */
-#define UO_RDWR			0x0002		/** read and write */
-#define UO_APPEND		0x0008		/** append */
+#define UO_RDONLY		DFS_O_RDONLY	/** read only */
+#define UO_WRONLY		DFS_O_WRONLY	/** write only */
+#define UO_RDWR			DFS_O_RDWR		/** read and write */
+#define UO_APPEND		DFS_O_APPEND	/** append */
+
+#define UO_BINARY		0x0000			/** no used in uffs */
 
-#define UO_BINARY		0x0000		/** no used in uffs */
+#define UO_CREATE		DFS_O_CREAT		
+#define UO_TRUNC		DFS_O_TRUNC		
+#define UO_EXCL			DFS_O_EXCL
 
-#define UO_CREATE		0x0100
-#define UO_TRUNC		0x0200
-#define UO_EXCL			0x0400		
+#define UO_DIR			DFS_O_DIRECTORY	/** open a directory */
 
-#define UO_DIR			0x1000		/** open a directory */
 
 
+#define UENOERR 		0	/** no error */
+#define UEACCES			1	/** Tried to open read-only file
+						 	for writing, or files sharing mode
+						 	does not allow specified operations,
+						 	or given path is directory */
 
-#define UENOERR 0		/** no error */
-#define UEACCES	1		/** Tried to open read-only file
-						 for writing, or files sharing mode
-						 does not allow specified operations,
-						 or given path is directory */
-
-#define UEEXIST	2		/** _O_CREAT and _O_EXCL flags specified,
+#define UEEXIST			2	/** _O_CREAT and _O_EXCL flags specified,
 							but filename already exists */
-#define UEINVAL	3		/** Invalid oflag or pmode argument */
-#define UEMFILE	4		/** No more file handles available
-						  (too many open files)  */
-#define UENOENT	5		/** file or path not found */
-#define UETIME	6		/** can't set file time */
-#define UEBADF	9		/** invalid file handle */
-#define UENOMEM	10		/** no enough memory */
-#define UEIOERR	11		/** I/O error from lower level flash operation */
-#define UENOTDIR 12		/** Not a directory */
-#define UEISDIR 13		/** Is a directory */    
-
-#define UEUNKNOWN	100	/** unknown error */
-
-
-
-#define _SEEK_CUR		0		/** seek from current position */
-#define _SEEK_SET		1		/** seek from beginning of file */
-#define _SEEK_END		2		/** seek from end of file */
-
-#define USEEK_CUR		_SEEK_CUR
-#define USEEK_SET		_SEEK_SET
-#define USEEK_END		_SEEK_END
-
-
-
-/** 
- * \def MAX_FILENAME_LENGTH 
- * \note Be careful: it's part of the physical format (see: uffs_FileInfoSt.name)
- *    !!DO NOT CHANGE IT AFTER FILE SYSTEM IS FORMATED!!
- */
-#define MAX_FILENAME_LENGTH			32
-
-/** \note 8-bits attr goes to uffs_dirent::d_type */
-#define FILE_ATTR_DIR		(1 << 7)	//!< attribute for directory
-#define FILE_ATTR_WRITE		(1 << 0)	//!< writable
-
-
-/**
- * \structure uffs_FileInfoSt
- * \brief file/dir entry info in physical storage format
- */
-struct uffs_FileInfoSt {
-	u32 attr;				//!< file/dir attribute
-	u32 create_time;
-	u32 last_modify;
-	u32 access;
-	u32 reserved;
-	u32 name_len;			//!< length of file/dir name
-	char name[MAX_FILENAME_LENGTH];
-};
-typedef struct uffs_FileInfoSt uffs_FileInfo;
-
-/**
- * \struct uffs_ObjectInfoSt
- * \brief object info
- */
-typedef struct uffs_ObjectInfoSt {
-	uffs_FileInfo info;
-	u32 len;				//!< length of file
-	u16 serial;				//!< object serial num
-} uffs_ObjectInfo;
+#define UEINVAL			3	/** Invalid oflag or pmode argument */
+#define UEMFILE			4	/** No more file handles available
+						  	(too many open files)  */
+#define UENOENT			5	/** file or path not found */
+#define UETIME			6	/** can't set file time */
+#define UEBADF			9	/** invalid file handle */
+#define UENOMEM			10	/** no enough memory */
+#define UEIOERR			11	/** I/O error from lower level flash operation */
+#define UENOTDIR 		12	/** Not a directory */
+#define UEISDIR 		13	/** Is a directory */ 
+
+#define UEUNKNOWN		100	/** unknown error */
+	
+
+#define _SEEK_CUR		0		/** seek from current position */
+#define _SEEK_SET		1		/** seek from beginning of file */
+#define _SEEK_END		2		/** seek from end of file */
+
+#define USEEK_SET		DFS_SEEK_SET  	/*0* 从当前点寻找 */
+#define USEEK_CUR		DFS_SEEK_CUR	/*1* 从文件的开始寻找 */
+#define USEEK_END		DFS_SEEK_END	/*2* 从文件的结尾寻找 */
+
+
+
+
+/** 
+ * \def MAX_FILENAME_LENGTH 
+ * \note Be careful: it's part of the physical format (see: uffs_FileInfoSt.name)
+ *    !!DO NOT CHANGE IT AFTER FILE SYSTEM IS FORMATED!!
+ */
+#define MAX_FILENAME_LENGTH			32
+
+/** \note 8-bits attr goes to uffs_dirent::d_type */
+#define FILE_ATTR_DIR		(1 << 7)	//!< attribute for directory
+#define FILE_ATTR_WRITE		(1 << 0)	//!< writable
+
 
+/*
+ * \structure uffs_FileInfoSt
+ * \brief file/dir entry info in physical storage format
+ */
+struct uffs_FileInfoSt {
+	u32 attr;				//!< file/dir attribute
+	u32 create_time;
+	u32 last_modify;
+	u32 access;
+	u32 reserved;
+	u32 name_len;			//!< length of file/dir name
+	char name[MAX_FILENAME_LENGTH];
+};
+typedef struct uffs_FileInfoSt uffs_FileInfo;
+
+/**
+ * \struct uffs_ObjectInfoSt
+ * \brief object info
+ */
+typedef struct uffs_ObjectInfoSt {
+	uffs_FileInfo info;
+	u32 len;				//!< length of file
+	u16 serial;				//!< object serial num
+} uffs_ObjectInfo;
+
 
 #ifdef __cplusplus
 }

+ 70 - 70
components/dfs/filesystems/uffs/src/inc/uffs/uffs_badblock.h

@@ -1,70 +1,70 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-/** 
- * \file uffs_badblock.h
- * \brief bad block management
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_BADBLOCK_H_
-#define _UFFS_BADBLOCK_H_
-
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#define HAVE_BADBLOCK(dev) (dev->bad.block != UFFS_INVALID_BLOCK)
-
-/** initialize bad block management data structures for uffs device */
-void uffs_BadBlockInit(uffs_Device *dev);
-
-/** processing bad block: erase bad block, mark it as 'bad' and put it to bad block list */
-void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node);
-
-/** try to recover data from a new discovered bad block */
-void uffs_BadBlockRecover(uffs_Device *dev);
-
-/** put a new block to the bad block waiting list */
-void uffs_BadBlockAdd(uffs_Device *dev, int block);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+/** 
+ * \file uffs_badblock.h
+ * \brief bad block management
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_BADBLOCK_H_
+#define _UFFS_BADBLOCK_H_
+
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#define HAVE_BADBLOCK(dev) (dev->bad.block != UFFS_INVALID_BLOCK)
+
+/** initialize bad block management data structures for uffs device */
+void uffs_BadBlockInit(uffs_Device *dev);
+
+/** processing bad block: erase bad block, mark it as 'bad' and put it to bad block list */
+void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node);
+
+/** try to recover data from a new discovered bad block */
+void uffs_BadBlockRecover(uffs_Device *dev);
+
+/** put a new block to the bad block waiting list */
+void uffs_BadBlockAdd(uffs_Device *dev, int block);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 107 - 107
components/dfs/filesystems/uffs/src/inc/uffs/uffs_blockinfo.h

@@ -1,107 +1,107 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-/** 
- * \file uffs_blockinfo.h
- * \brief data structure for operating block information
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_BLOCKINFO_H_
-#define _UFFS_BLOCKINFO_H_
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-/** 
- * \struct uffs_PageSpareSt
- * \brief this structure is for storing uffs tag and more. 
- */
-struct uffs_PageSpareSt {
-	uffs_Tags tag;			//!< page tag
-	u8 expired:1;
-};
-
-/** 
- * \struct uffs_BlockInfoSt
- * \brief block information data. Block info is frequently accessed,
-          UFFS use a cache system to speed up block info access.
- */
-struct uffs_BlockInfoSt {
-	struct uffs_BlockInfoSt *next;
-	struct uffs_BlockInfoSt *prev;
-	u16 block;							//!< block number
-	struct uffs_PageSpareSt *spares;	//!< page spare info array
-	int expired_count;					//!< how many pages expired in this block ? 
-	int ref_count;						//!< reference counter, it's safe to reuse this block memory when the counter is 0.
-};
-
-/** get tag from block info */
-#define GET_TAG(bc, page) (&(bc)->spares[page].tag)
-
-
-/** initialize block info caches */
-URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks);
-
-/** release block info caches */
-URET uffs_BlockInfoReleaseCache(uffs_Device *dev);
-
-/** load page spare to block info cache */
-URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page);
-
-/** find block info cache */
-uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block);
-
-/** get block info cache, load it on demand */
-uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block);
-
-/** put info cache back to pool, should be called with #uffs_BlockInfoGet in pairs. */
-void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p);
-
-/** explicitly expire a block info cache */
-void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page);
-
-/** no one hold any block info cache ? safe to release block info caches */
-UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev);
-
-/** explicitly expire all block info caches */
-void uffs_BlockInfoExpireAll(uffs_Device *dev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+/** 
+ * \file uffs_blockinfo.h
+ * \brief data structure for operating block information
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_BLOCKINFO_H_
+#define _UFFS_BLOCKINFO_H_
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+/** 
+ * \struct uffs_PageSpareSt
+ * \brief this structure is for storing uffs tag and more. 
+ */
+struct uffs_PageSpareSt {
+	uffs_Tags tag;			//!< page tag
+	u8 expired:1;
+};
+
+/** 
+ * \struct uffs_BlockInfoSt
+ * \brief block information data. Block info is frequently accessed,
+          UFFS use a cache system to speed up block info access.
+ */
+struct uffs_BlockInfoSt {
+	struct uffs_BlockInfoSt *next;
+	struct uffs_BlockInfoSt *prev;
+	u16 block;							//!< block number
+	struct uffs_PageSpareSt *spares;	//!< page spare info array
+	int expired_count;					//!< how many pages expired in this block ? 
+	int ref_count;						//!< reference counter, it's safe to reuse this block memory when the counter is 0.
+};
+
+/** get tag from block info */
+#define GET_TAG(bc, page) (&(bc)->spares[page].tag)
+
+
+/** initialize block info caches */
+URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks);
+
+/** release block info caches */
+URET uffs_BlockInfoReleaseCache(uffs_Device *dev);
+
+/** load page spare to block info cache */
+URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page);
+
+/** find block info cache */
+uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block);
+
+/** get block info cache, load it on demand */
+uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block);
+
+/** put info cache back to pool, should be called with #uffs_BlockInfoGet in pairs. */
+void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p);
+
+/** explicitly expire a block info cache */
+void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page);
+
+/** no one hold any block info cache ? safe to release block info caches */
+UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev);
+
+/** explicitly expire all block info caches */
+void uffs_BlockInfoExpireAll(uffs_Device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 174 - 174
components/dfs/filesystems/uffs/src/inc/uffs/uffs_buf.h

@@ -1,174 +1,174 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_buf.h
- * \brief page buffers
- * \author Ricky Zheng
- */
-
-#ifndef UFFS_BUF_H
-#define UFFS_BUF_H
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_tree.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-	
-#define CLONE_BUF_MARK		0xffff		//!< set uffs_BufSt::ref_count to this for a 'cloned' buffer
-
-/** for uffs_BufSt::mark */
-#define UFFS_BUF_EMPTY		0			//!< buffer is empty
-#define UFFS_BUF_VALID		1			//!< buffer is holding valid data
-#define UFFS_BUF_DIRTY		2			//!< buffer data is modified
-
-/** for uffs_BufSt::ext_mark */
-#define UFFS_BUF_EXT_MARK_TRUNC_TAIL		1	//!<
-
-/** uffs page buffer */
-struct uffs_BufSt{
-	struct uffs_BufSt *next;			//!< link to next buffer
-	struct uffs_BufSt *prev;			//!< link to previous buffer
-	struct uffs_BufSt *next_dirty;		//!< link to next dirty buffer
-	struct uffs_BufSt *prev_dirty;		//!< link to previous dirty buffer
-	u8 type;							//!< #UFFS_TYPE_DIR or #UFFS_TYPE_FILE or #UFFS_TYPE_DATA
-	u16 parent;							//!< parent serial
-	u16 serial;							//!< serial 
-	u16 page_id;						//!< page id 
-	u16 mark;							//!< #UFFS_BUF_EMPTY or #UFFS_BUF_VALID, or #UFFS_BUF_DIRTY ?
-	u16 ref_count;						//!< reference counter, or #CLONE_BUF_MARK for a cloned buffer
-	u16 data_len;						//!< length of data
-	u16 check_sum;						//!< checksum field
-	u8 * data;							//!< data buffer
-	u8 * header;						//!< header
-	int ext_mark;						//!< extension mark. 
-};
-
-#define uffs_BufIsFree(buf) (buf->ref_count == 0 ? U_TRUE : U_FALSE)
-
-/** initialize page buffers */
-URET uffs_BufInit(struct uffs_DeviceSt *dev, int buf_max, int dirty_buf_max);
-
-/** release page buffers */
-URET uffs_BufReleaseAll(struct uffs_DeviceSt *dev);
-
-/** find the page buffer, move to link list head if found */
-uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 parent, u16 serial, u16 page_id);
-uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 page_id);
-
-/** alloc a new page buffer */
-uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 parent, u16 serial, u16 page_id);
-
-/** find the page buffer (not affect the reference counter) */
-uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 parent, u16 serial, u16 page_id);
-
-/** put page buffer back to pool, called in pair with #uffs_Get,#uffs_GetEx or #uffs_BufNew */
-URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf);
-
-/** increase buffer references */
-void uffs_BufIncRef(uffs_Buf *buf);
-
-/** decrease buffer references */
-void uffs_BufDecRef(uffs_Buf *buf);
-
-/** write data to a page buffer */
-URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
-
-/** read data from a page buffer */
-URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
-
-/** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0, and discard all data it holds */
-void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf);
-
-/** if there is no free dirty group slot, flush the most dirty group */
-URET uffs_BufFlush(struct uffs_DeviceSt *dev);
-URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover);
-
-/** flush dirty group */
-URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
-URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev, u16 parent, u16 serial, UBOOL force_block_recover);
-
-/** find free dirty group slot */
-int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev);
-
-/** find the dirty group slot */
-int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
-
-/** lock dirty group */
-URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot);
-
-/** unlock dirty group */
-URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot);
-
-/** flush most dirty group */
-URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev);
-
-/** flush all groups under the same parent number */
-URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent);
-
-/** flush all page buffers */
-URET uffs_BufFlushAll(struct uffs_DeviceSt *dev);
-
-/** no one holding any page buffer ? safe to release page buffers */
-UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev);
-
-/** are all page buffer marked with #UFFS_BUF_EMPTY ? */
-UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev);
-
-/** mark all page buffer as #UFFS_BUF_EMPTY */
-URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev);
-
-/** clone a page buffer */
-uffs_Buf * uffs_BufClone(struct uffs_DeviceSt *dev, uffs_Buf *buf);
-
-/** release a cloned page buffer, call in pair with #uffs_BufClone */
-URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf);
-
-/** load physical storage data to page buffer */
-URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
-
-/** load physical storage data to page buffer withouth checking ECC */
-URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
-
-/** showing page buffers info, for debug only */
-void uffs_BufInspect(uffs_Device *dev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_buf.h
+ * \brief page buffers
+ * \author Ricky Zheng
+ */
+
+#ifndef UFFS_BUF_H
+#define UFFS_BUF_H
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_tree.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+	
+#define CLONE_BUF_MARK		0xffff		//!< set uffs_BufSt::ref_count to this for a 'cloned' buffer
+
+/** for uffs_BufSt::mark */
+#define UFFS_BUF_EMPTY		0			//!< buffer is empty
+#define UFFS_BUF_VALID		1			//!< buffer is holding valid data
+#define UFFS_BUF_DIRTY		2			//!< buffer data is modified
+
+/** for uffs_BufSt::ext_mark */
+#define UFFS_BUF_EXT_MARK_TRUNC_TAIL		1	//!<
+
+/** uffs page buffer */
+struct uffs_BufSt{
+	struct uffs_BufSt *next;			//!< link to next buffer
+	struct uffs_BufSt *prev;			//!< link to previous buffer
+	struct uffs_BufSt *next_dirty;		//!< link to next dirty buffer
+	struct uffs_BufSt *prev_dirty;		//!< link to previous dirty buffer
+	u8 type;							//!< #UFFS_TYPE_DIR or #UFFS_TYPE_FILE or #UFFS_TYPE_DATA
+	u16 parent;							//!< parent serial
+	u16 serial;							//!< serial 
+	u16 page_id;						//!< page id 
+	u16 mark;							//!< #UFFS_BUF_EMPTY or #UFFS_BUF_VALID, or #UFFS_BUF_DIRTY ?
+	u16 ref_count;						//!< reference counter, or #CLONE_BUF_MARK for a cloned buffer
+	u16 data_len;						//!< length of data
+	u16 check_sum;						//!< checksum field
+	u8 * data;							//!< data buffer
+	u8 * header;						//!< header
+	int ext_mark;						//!< extension mark. 
+};
+
+#define uffs_BufIsFree(buf) (buf->ref_count == 0 ? U_TRUE : U_FALSE)
+
+/** initialize page buffers */
+URET uffs_BufInit(struct uffs_DeviceSt *dev, int buf_max, int dirty_buf_max);
+
+/** release page buffers */
+URET uffs_BufReleaseAll(struct uffs_DeviceSt *dev);
+
+/** find the page buffer, move to link list head if found */
+uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 parent, u16 serial, u16 page_id);
+uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 page_id);
+
+/** alloc a new page buffer */
+uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 parent, u16 serial, u16 page_id);
+
+/** find the page buffer (not affect the reference counter) */
+uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 parent, u16 serial, u16 page_id);
+
+/** put page buffer back to pool, called in pair with #uffs_Get,#uffs_GetEx or #uffs_BufNew */
+URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf);
+
+/** increase buffer references */
+void uffs_BufIncRef(uffs_Buf *buf);
+
+/** decrease buffer references */
+void uffs_BufDecRef(uffs_Buf *buf);
+
+/** write data to a page buffer */
+URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
+
+/** read data from a page buffer */
+URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
+
+/** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0, and discard all data it holds */
+void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf);
+
+/** if there is no free dirty group slot, flush the most dirty group */
+URET uffs_BufFlush(struct uffs_DeviceSt *dev);
+URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover);
+
+/** flush dirty group */
+URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
+URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev, u16 parent, u16 serial, UBOOL force_block_recover);
+
+/** find free dirty group slot */
+int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev);
+
+/** find the dirty group slot */
+int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
+
+/** lock dirty group */
+URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot);
+
+/** unlock dirty group */
+URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot);
+
+/** flush most dirty group */
+URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev);
+
+/** flush all groups under the same parent number */
+URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent);
+
+/** flush all page buffers */
+URET uffs_BufFlushAll(struct uffs_DeviceSt *dev);
+
+/** no one holding any page buffer ? safe to release page buffers */
+UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev);
+
+/** are all page buffer marked with #UFFS_BUF_EMPTY ? */
+UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev);
+
+/** mark all page buffer as #UFFS_BUF_EMPTY */
+URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev);
+
+/** clone a page buffer */
+uffs_Buf * uffs_BufClone(struct uffs_DeviceSt *dev, uffs_Buf *buf);
+
+/** release a cloned page buffer, call in pair with #uffs_BufClone */
+URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf);
+
+/** load physical storage data to page buffer */
+URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
+
+/** load physical storage data to page buffer withouth checking ECC */
+URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
+
+/** showing page buffers info, for debug only */
+void uffs_BufInspect(uffs_Device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 277 - 277
components/dfs/filesystems/uffs/src/inc/uffs/uffs_config.h

@@ -1,277 +1,277 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_config.h
- * \brief basic configuration of uffs
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_CONFIG_H_
-#define _UFFS_CONFIG_H_
-
-/**
- * \def UFFS_MAX_PAGE_SIZE
- * \note maximum page size UFFS support
- */
-#define UFFS_MAX_PAGE_SIZE		2048
-
-/**
- * \def UFFS_MAX_SPARE_SIZE
- */
-#define UFFS_MAX_SPARE_SIZE ((UFFS_MAX_PAGE_SIZE / 256) * 8)
-
-/**
- * \def MAX_CACHED_BLOCK_INFO
- * \note uffs cache the block info for opened directories and files,
- *       a practical value is 5 ~ MAX_OBJECT_HANDLE
- */
-#define MAX_CACHED_BLOCK_INFO	10
-
-/** 
- * \def MAX_PAGE_BUFFERS
- * \note the bigger value will bring better read/write performance.
- *       but few writing performance will be improved when this 
- *       value is become larger than 'max pages per block'
- */
-#define MAX_PAGE_BUFFERS		10
-
-
-/** 
- * \def CLONE_BUFFER_THRESHOLD
- * \note reserve buffers for clone. 1 or 2 should be enough.
- */
-#define CLONE_BUFFERS_THRESHOLD	2
-
-/**
- * \def MAX_SPARE_BUFFERS
- * \note spare buffers are used for lower level flash operations, 5 should be enough.
- */
-#define MAX_SPARE_BUFFERS		5
-
-
-/**
- * \def MAX_DIRTY_PAGES_IN_A_BLOCK 
- * \note this value should be between '2' and the lesser of 'max pages per block' and (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1).
- *       the smaller the value the frequently the buffer will be flushed.
- */
-#define MAX_DIRTY_PAGES_IN_A_BLOCK	7
-
-/**
- * \def MAX_DIRTY_BUF_GROUPS
- */
-#define MAX_DIRTY_BUF_GROUPS	3
-
-
-/**
- * \def CONFIG_USE_STATIC_MEMORY_ALLOCATOR
- * \note uffs will use static memory allocator if this is defined.
- *       to use static memory allocator, you need to provide memory
- *       buffer when creating uffs_Device.
- *
- *       use UFFS_STATIC_BUFF_SIZE() to calculate memory buffer size.
- */
-#define CONFIG_USE_STATIC_MEMORY_ALLOCATOR 0
-
-/**
- * \def CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
- * \note  the native memory allocator should only be used for
- *        tracking memory leak bugs or tracking memory consuming.
- *        In your final product, you either disable the native memory
- *        allocator or use the system heap as the memory pool for the
- *        native memory allocator.
- */
-#define CONFIG_USE_NATIVE_MEMORY_ALLOCATOR 0
-
-
-/**
- * \def CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR
- * \note  using system platform's 'malloc' and 'free'.
- */
-#define CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR 1
-
-
-
-/** 
- * \def CONFIG_FLUSH_BUF_AFTER_WRITE
- * \note UFFS will write all data directly into flash in 
- *       each 'write' call if you enable this option.
- *       (which means lesser data lost when power failue but
- *		 pooer writing performance).
- *		 It's not recommented to open this define for normal applications.
- */
-//#define CONFIG_FLUSH_BUF_AFTER_WRITE
-
-/**
- * \def CONFIG_TREE_NODE_USE_DOUBLE_LINK
- * \note: enable double link tree node will speed up insert/delete operation,
- */
-#define CONFIG_TREE_NODE_USE_DOUBLE_LINK
-
-/** 
- * \def MAX_OBJECT_HANDLE
- * maximum number of object handle 
- */
-#define MAX_OBJECT_HANDLE	10
-
-/**
- * \def MAX_DIR_HANDLE
- * maximum number of uffs_DIR
- */
-#define MAX_DIR_HANDLE	5
-
-/**
- * \def MINIMUN_ERASED_BLOCK
- *  UFFS will not allow appending or creating new files when the free/erased block
- *  is lower then MINIMUN_ERASED_BLOCK.
- */
-#define MINIMUN_ERASED_BLOCK 2
-
-/**
- * \def CONFIG_CHANGE_MODIFY_TIME
- * \note If defined, closing a file which is opened for writing/appending will
- *       update the file's modify time as well. Disable this feature will save a
- *       lot of writing activities if you frequently open files for write and close it.
- */
-//#define CONFIG_CHANGE_MODIFY_TIME
-
-
-/**
- * \def CONFIG_ENABLE_BAD_BLOCK_VERIFY
- * \note allow erase and verify block marked as 'bad' when format UFFS partition.
- *		it's not recommented for most NAND flash.
- */
-#define CONFIG_ENABLE_BAD_BLOCK_VERIFY
-
-/**
- * \def CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
- * \note erase block again before mark bad block
- */
-#define CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
-
-/**
- * \def CONFIG_PAGE_WRITE_VERIFY
- * \note verify page data after write, for extra safe data storage.
- */
-#define CONFIG_PAGE_WRITE_VERIFY
-
-/**
- * \def CONFIG_BAD_BLOCK_POLICY_STRICT
- * \note If this is enabled, UFFS will report the block as 'bad' if any bit-flips found;
- *       otherwise, UFFS report bad block only when ECC failed or reported by low level flash driver.
- *
- * \note Enable this will ensure your data always be stored on completly good blocks.
- */
-#define CONFIG_BAD_BLOCK_POLICY_STRICT
-
-
-
-/** micros for calculating buffer sizes */
-
-/**
- *	\def UFFS_BLOCK_INFO_BUFFER_SIZE
- *	\brief calculate memory bytes for block info caches
- */
-#define UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block)	\
-			(											\
-				(										\
-					sizeof(uffs_BlockInfo) +			\
-					sizeof(uffs_PageSpare) * n_pages_per_block \
-				 ) * MAX_CACHED_BLOCK_INFO				\
-			)
-
-/**
- *	\def UFFS_PAGE_BUFFER_SIZE
- *	\brief calculate memory bytes for page buffers
- */
-#define UFFS_PAGE_BUFFER_SIZE(n_page_size)	\
-			(								\
-				(							\
-					sizeof(uffs_Buf) + n_page_size	\
-				) * MAX_PAGE_BUFFERS		\
-			)
-
-/**
- *	\def UFFS_TREE_BUFFER_SIZE
- *	\brief calculate memory bytes for tree nodes
- */
-#define UFFS_TREE_BUFFER_SIZE(n_blocks) (sizeof(TreeNode) * n_blocks)
-
-
-#define UFFS_SPARE_BUFFER_SIZE (MAX_SPARE_BUFFERS * UFFS_MAX_SPARE_SIZE)
-
-
-/**
- *	\def UFFS_STATIC_BUFF_SIZE
- *	\brief calculate total memory usage of uffs system
- */
-#define UFFS_STATIC_BUFF_SIZE(n_pages_per_block, n_page_size, n_blocks) \
-			(		\
-				UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block) + \
-				UFFS_PAGE_BUFFER_SIZE(n_page_size) + \
-				UFFS_TREE_BUFFER_SIZE(n_blocks) + \
-				UFFS_SPARE_BUFFER_SIZE \
-			 )
-
-
-
-/* config check */
-#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD) < 3
-#error "MAX_PAGE_BUFFERS is too small"
-#endif
-
-#if (MAX_DIRTY_PAGES_IN_A_BLOCK < 2)
-#error "MAX_DIRTY_PAGES_IN_A_BLOCK should >= 2"
-#endif
-
-#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1 < MAX_DIRTY_PAGES_IN_A_BLOCK)
-#error "MAX_DIRTY_PAGES_IN_A_BLOCK should < (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD)"
-#endif
-
-#if defined(CONFIG_PAGE_WRITE_VERIFY) && (CLONE_BUFFERS_THRESHOLD < 2)
-#error "CLONE_BUFFERS_THRESHOLD should >= 2 when CONFIG_PAGE_WRITE_VERIFY is enabled."
-#endif
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 1
-#error "Please enable ONLY one memory allocator"
-#endif
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR == 0
-#error "Please enable ONE of memory allocators"
-#endif
-
-
-#ifdef WIN32
-# pragma warning(disable : 4996)
-#endif
-
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_config.h
+ * \brief basic configuration of uffs
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_CONFIG_H_
+#define _UFFS_CONFIG_H_
+
+/**
+ * \def UFFS_MAX_PAGE_SIZE
+ * \note maximum page size UFFS support
+ */
+#define UFFS_MAX_PAGE_SIZE		2048
+
+/**
+ * \def UFFS_MAX_SPARE_SIZE
+ */
+#define UFFS_MAX_SPARE_SIZE ((UFFS_MAX_PAGE_SIZE / 256) * 8)
+
+/**
+ * \def MAX_CACHED_BLOCK_INFO
+ * \note uffs cache the block info for opened directories and files,
+ *       a practical value is 5 ~ MAX_OBJECT_HANDLE
+ */
+#define MAX_CACHED_BLOCK_INFO	10
+
+/** 
+ * \def MAX_PAGE_BUFFERS
+ * \note the bigger value will bring better read/write performance.
+ *       but few writing performance will be improved when this 
+ *       value is become larger than 'max pages per block'
+ */
+#define MAX_PAGE_BUFFERS		10
+
+
+/** 
+ * \def CLONE_BUFFER_THRESHOLD
+ * \note reserve buffers for clone. 1 or 2 should be enough.
+ */
+#define CLONE_BUFFERS_THRESHOLD	2
+
+/**
+ * \def MAX_SPARE_BUFFERS
+ * \note spare buffers are used for lower level flash operations, 5 should be enough.
+ */
+#define MAX_SPARE_BUFFERS		5
+
+
+/**
+ * \def MAX_DIRTY_PAGES_IN_A_BLOCK 
+ * \note this value should be between '2' and the lesser of 'max pages per block' and (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1).
+ *       the smaller the value the frequently the buffer will be flushed.
+ */
+#define MAX_DIRTY_PAGES_IN_A_BLOCK	7
+
+/**
+ * \def MAX_DIRTY_BUF_GROUPS
+ */
+#define MAX_DIRTY_BUF_GROUPS	3
+
+
+/**
+ * \def CONFIG_USE_STATIC_MEMORY_ALLOCATOR
+ * \note uffs will use static memory allocator if this is defined.
+ *       to use static memory allocator, you need to provide memory
+ *       buffer when creating uffs_Device.
+ *
+ *       use UFFS_STATIC_BUFF_SIZE() to calculate memory buffer size.
+ */
+#define CONFIG_USE_STATIC_MEMORY_ALLOCATOR 0
+
+/**
+ * \def CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
+ * \note  the native memory allocator should only be used for
+ *        tracking memory leak bugs or tracking memory consuming.
+ *        In your final product, you either disable the native memory
+ *        allocator or use the system heap as the memory pool for the
+ *        native memory allocator.
+ */
+#define CONFIG_USE_NATIVE_MEMORY_ALLOCATOR 0
+
+
+/**
+ * \def CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR
+ * \note  using system platform's 'malloc' and 'free'.
+ */
+#define CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR 1
+
+
+
+/** 
+ * \def CONFIG_FLUSH_BUF_AFTER_WRITE
+ * \note UFFS will write all data directly into flash in 
+ *       each 'write' call if you enable this option.
+ *       (which means lesser data lost when power failue but
+ *		 pooer writing performance).
+ *		 It's not recommented to open this define for normal applications.
+ */
+//#define CONFIG_FLUSH_BUF_AFTER_WRITE
+
+/**
+ * \def CONFIG_TREE_NODE_USE_DOUBLE_LINK
+ * \note: enable double link tree node will speed up insert/delete operation,
+ */
+#define CONFIG_TREE_NODE_USE_DOUBLE_LINK
+
+/** 
+ * \def MAX_OBJECT_HANDLE
+ * maximum number of object handle 
+ */
+#define MAX_OBJECT_HANDLE	10
+
+/**
+ * \def MAX_DIR_HANDLE
+ * maximum number of uffs_DIR
+ */
+#define MAX_DIR_HANDLE	5
+
+/**
+ * \def MINIMUN_ERASED_BLOCK
+ *  UFFS will not allow appending or creating new files when the free/erased block
+ *  is lower then MINIMUN_ERASED_BLOCK.
+ */
+#define MINIMUN_ERASED_BLOCK 2
+
+/**
+ * \def CONFIG_CHANGE_MODIFY_TIME
+ * \note If defined, closing a file which is opened for writing/appending will
+ *       update the file's modify time as well. Disable this feature will save a
+ *       lot of writing activities if you frequently open files for write and close it.
+ */
+//#define CONFIG_CHANGE_MODIFY_TIME
+
+
+/**
+ * \def CONFIG_ENABLE_BAD_BLOCK_VERIFY
+ * \note allow erase and verify block marked as 'bad' when format UFFS partition.
+ *		it's not recommented for most NAND flash.
+ */
+#define CONFIG_ENABLE_BAD_BLOCK_VERIFY
+
+/**
+ * \def CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
+ * \note erase block again before mark bad block
+ */
+#define CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
+
+/**
+ * \def CONFIG_PAGE_WRITE_VERIFY
+ * \note verify page data after write, for extra safe data storage.
+ */
+#define CONFIG_PAGE_WRITE_VERIFY
+
+/**
+ * \def CONFIG_BAD_BLOCK_POLICY_STRICT
+ * \note If this is enabled, UFFS will report the block as 'bad' if any bit-flips found;
+ *       otherwise, UFFS report bad block only when ECC failed or reported by low level flash driver.
+ *
+ * \note Enable this will ensure your data always be stored on completly good blocks.
+ */
+//#define CONFIG_BAD_BLOCK_POLICY_STRICT
+
+
+
+/** micros for calculating buffer sizes */
+
+/**
+ *	\def UFFS_BLOCK_INFO_BUFFER_SIZE
+ *	\brief calculate memory bytes for block info caches
+ */
+#define UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block)	\
+			(											\
+				(										\
+					sizeof(uffs_BlockInfo) +			\
+					sizeof(uffs_PageSpare) * n_pages_per_block \
+				 ) * MAX_CACHED_BLOCK_INFO				\
+			)
+
+/**
+ *	\def UFFS_PAGE_BUFFER_SIZE
+ *	\brief calculate memory bytes for page buffers
+ */
+#define UFFS_PAGE_BUFFER_SIZE(n_page_size)	\
+			(								\
+				(							\
+					sizeof(uffs_Buf) + n_page_size	\
+				) * MAX_PAGE_BUFFERS		\
+			)
+
+/**
+ *	\def UFFS_TREE_BUFFER_SIZE
+ *	\brief calculate memory bytes for tree nodes
+ */
+#define UFFS_TREE_BUFFER_SIZE(n_blocks) (sizeof(TreeNode) * n_blocks)
+
+
+#define UFFS_SPARE_BUFFER_SIZE (MAX_SPARE_BUFFERS * UFFS_MAX_SPARE_SIZE)
+
+
+/**
+ *	\def UFFS_STATIC_BUFF_SIZE
+ *	\brief calculate total memory usage of uffs system
+ */
+#define UFFS_STATIC_BUFF_SIZE(n_pages_per_block, n_page_size, n_blocks) \
+			(		\
+				UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block) + \
+				UFFS_PAGE_BUFFER_SIZE(n_page_size) + \
+				UFFS_TREE_BUFFER_SIZE(n_blocks) + \
+				UFFS_SPARE_BUFFER_SIZE \
+			 )
+
+
+
+/* config check */
+#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD) < 3
+#error "MAX_PAGE_BUFFERS is too small"
+#endif
+
+#if (MAX_DIRTY_PAGES_IN_A_BLOCK < 2)
+#error "MAX_DIRTY_PAGES_IN_A_BLOCK should >= 2"
+#endif
+
+#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1 < MAX_DIRTY_PAGES_IN_A_BLOCK)
+#error "MAX_DIRTY_PAGES_IN_A_BLOCK should < (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD)"
+#endif
+
+#if defined(CONFIG_PAGE_WRITE_VERIFY) && (CLONE_BUFFERS_THRESHOLD < 2)
+#error "CLONE_BUFFERS_THRESHOLD should >= 2 when CONFIG_PAGE_WRITE_VERIFY is enabled."
+#endif
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 1
+#error "Please enable ONLY one memory allocator"
+#endif
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR == 0
+#error "Please enable ONE of memory allocators"
+#endif
+
+
+#ifdef WIN32
+# pragma warning(disable : 4996)
+#endif
+
+#endif

+ 59 - 59
components/dfs/filesystems/uffs/src/inc/uffs/uffs_core.h

@@ -1,59 +1,59 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef _UFFS_CORE_H_
-#define _UFFS_CORE_H_
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-/** \typedef uffs_Device */
-typedef struct uffs_DeviceSt		uffs_Device;
-/** \typedef uffs_FlashOps */
-typedef struct uffs_FlashOpsSt		uffs_FlashOps;
-
-typedef struct uffs_BlockInfoSt uffs_BlockInfo;
-typedef struct uffs_PageSpareSt uffs_PageSpare;
-typedef struct uffs_TagsSt			uffs_Tags;		//!< UFFS page tags
-typedef struct uffs_TagStoreSt      uffs_TagStore;  //!< UFFS page tags physical store structure
-
-typedef struct uffs_BufSt uffs_Buf;
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef _UFFS_CORE_H_
+#define _UFFS_CORE_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/** \typedef uffs_Device */
+typedef struct uffs_DeviceSt		uffs_Device;
+/** \typedef uffs_FlashOps */
+typedef struct uffs_FlashOpsSt		uffs_FlashOps;
+
+typedef struct uffs_BlockInfoSt 	uffs_BlockInfo;
+typedef struct uffs_PageSpareSt 	uffs_PageSpare;
+typedef struct uffs_TagsSt			uffs_Tags;		//!< UFFS page tags
+typedef struct uffs_TagStoreSt      uffs_TagStore;  //!< UFFS page tags physical store structure
+
+typedef struct uffs_BufSt 			uffs_Buf;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif

+ 191 - 191
components/dfs/filesystems/uffs/src/inc/uffs/uffs_device.h

@@ -1,191 +1,191 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_device.h
- * \brief uffs device structures definition
- * \author Ricky Zheng
- */
-
-#ifndef UFFS_DEVICE_H
-#define UFFS_DEVICE_H
-
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_buf.h"
-#include "uffs/uffs_blockinfo.h"
-#include "uffs/uffs_pool.h"
-#include "uffs/uffs_tree.h"
-#include "uffs/uffs_mem.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs_flash.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-
-/** 
- * \struct uffs_BlockInfoCacheSt
- * \brief block information structure, used to manager block information caches
- */
-struct uffs_BlockInfoCacheSt {
-	uffs_BlockInfo *head;			//!< buffer head of block info(spares)
-	uffs_BlockInfo *tail;			//!< buffer tail
-	void *mem_pool;					//!< internal memory pool, used for release whole buffer
-};
-
-/** 
- * \struct uffs_PartitionSt
- * \brief partition basic information
- */
-struct uffs_PartitionSt {
-	u16 start;		//!< start block number of partition
-	u16 end;		//!< end block number of partiton
-};
-
-/** 
- * \struct uffs_LockSt
- * \brief lock stuffs
- */
-struct uffs_LockSt {
-	int sem;
-	int task_id;
-	int counter;
-};
-
-/** 
- * \struct uffs_DirtyGroupSt
- * \brief manager dirty page buffers
- */
-struct uffs_DirtyGroupSt {
-	int count;					//!< dirty buffers count
-	int lock;					//!< dirty group lock (0: unlocked, >0: locked)
-	uffs_Buf *dirty;			//!< dirty buffer list
-};
-
-/** 
- * \struct uffs_PageBufDescSt
- * \brief uffs page buffers descriptor
- */
-struct uffs_PageBufDescSt {
-	uffs_Buf *head;			//!< head of buffers
-	uffs_Buf *tail;			//!< tail of buffers
-	struct uffs_DirtyGroupSt dirtyGroup[MAX_DIRTY_BUF_GROUPS];	//!< dirty buffer groups
-	int buf_max;			//!< maximum buffers
-	int dirty_buf_max;		//!< maximum dirty buffer allowed
-	void *pool;				//!< memory pool for buffers
-};
-
-
-/** 
- * \struct uffs_PageCommInfoSt
- * \brief common data for device, should be initialized at early
- * \note it is possible that pg_size is smaller than physical page size, but normally they are the same.
- * \note page data layout: [HEADER] + [DATA]
- */
-struct uffs_PageCommInfoSt {
-	u16 pg_data_size;			//!< page data size
-	u16 header_size;			//!< header size
-	u16 pg_size;				//!< page size
-};
-
-/** 
- * \struct uffs_NewBadBlockSt
- * \brief holding new discovered bad block
- */
-struct uffs_NewBadBlockSt {
-	u16 block;				//!< bad block, FIX ME to process more than one bad block
-};
-
-/**
- * \struct uffs_FlashStatSt
- * \typedef uffs_FlashStat
- * \brief statistic data of flash read/write/erase activities
- */
-typedef struct uffs_FlashStatSt {
-	int block_erase_count;
-	int page_write_count;
-	int page_read_count;
-	int page_header_read_count;
-	int spare_write_count;
-	int spare_read_count;
-} uffs_FlashStat;
-
-
-/** 
- * \struct uffs_DeviceSt
- * \brief The core data structure of UFFS, all information needed by manipulate UFFS object
- * \note one partition corresponding one uffs device.
- */
-struct uffs_DeviceSt {
-	URET (*Init)(uffs_Device *dev);				//!< low level initialization
-	URET (*Release)(uffs_Device *dev);			//!< low level release
-	void *_private;								//!< private data for device
-
-	struct uffs_StorageAttrSt		*attr;		//!< storage attribute
-	struct uffs_PartitionSt			par;		//!< partition information
-	struct uffs_FlashOpsSt			*ops;		//!< flash operations
-	struct uffs_BlockInfoCacheSt	bc;			//!< block info cache
-	struct uffs_LockSt				lock;		//!< lock data structure
-	struct uffs_PageBufDescSt		buf;		//!< page buffers
-	struct uffs_PageCommInfoSt		com;		//!< common information
-	struct uffs_TreeSt				tree;		//!< tree list of block
-	struct uffs_NewBadBlockSt		bad;		//!< new discovered bad block
-	struct uffs_FlashStatSt			st;			//!< statistic (counters)
-	struct uffs_memAllocatorSt		mem;		//!< uffs native memory allocator
-	u32	ref_count;								//!< device reference count
-	int	dev_num;								//!< device number (partition number)	
-};
-
-/** create the lock for uffs device */
-URET uffs_DeviceInitLock(uffs_Device *dev);
-
-/** delete the lock of uffs device */
-URET uffs_DeviceReleaseLock(uffs_Device *dev);
-
-/** lock uffs device */
-URET uffs_DeviceLock(uffs_Device *dev);
-
-/** unlock uffs device */
-URET uffs_DeviceUnLock(uffs_Device *dev);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_device.h
+ * \brief uffs device structures definition
+ * \author Ricky Zheng
+ */
+
+#ifndef UFFS_DEVICE_H
+#define UFFS_DEVICE_H
+
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_buf.h"
+#include "uffs/uffs_blockinfo.h"
+#include "uffs/uffs_pool.h"
+#include "uffs/uffs_tree.h"
+#include "uffs/uffs_mem.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_flash.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+
+/** 
+ * \struct uffs_BlockInfoCacheSt
+ * \brief block information structure, used to manager block information caches
+ */
+struct uffs_BlockInfoCacheSt {
+	uffs_BlockInfo *head;			//!< buffer head of block info(spares)
+	uffs_BlockInfo *tail;			//!< buffer tail
+	void *mem_pool;					//!< internal memory pool, used for release whole buffer
+};
+
+/** 
+ * \struct uffs_PartitionSt
+ * \brief partition basic information
+ */
+struct uffs_PartitionSt {
+	u16 start;		//!< start block number of partition
+	u16 end;		//!< end block number of partiton
+};
+
+/** 
+ * \struct uffs_LockSt
+ * \brief lock stuffs
+ */
+struct uffs_LockSt {
+	int sem;
+	int task_id;
+	int counter;
+};
+
+/** 
+ * \struct uffs_DirtyGroupSt
+ * \brief manager dirty page buffers
+ */
+struct uffs_DirtyGroupSt {
+	int count;					//!< dirty buffers count
+	int lock;					//!< dirty group lock (0: unlocked, >0: locked)
+	uffs_Buf *dirty;			//!< dirty buffer list
+};
+
+/** 
+ * \struct uffs_PageBufDescSt
+ * \brief uffs page buffers descriptor
+ */
+struct uffs_PageBufDescSt {
+	uffs_Buf *head;			//!< head of buffers
+	uffs_Buf *tail;			//!< tail of buffers
+	struct uffs_DirtyGroupSt dirtyGroup[MAX_DIRTY_BUF_GROUPS];	//!< dirty buffer groups
+	int buf_max;			//!< maximum buffers
+	int dirty_buf_max;		//!< maximum dirty buffer allowed
+	void *pool;				//!< memory pool for buffers
+};
+
+
+/** 
+ * \struct uffs_PageCommInfoSt
+ * \brief common data for device, should be initialized at early
+ * \note it is possible that pg_size is smaller than physical page size, but normally they are the same.
+ * \note page data layout: [HEADER] + [DATA]
+ */
+struct uffs_PageCommInfoSt {
+	u16 pg_data_size;			//!< page data size
+	u16 header_size;			//!< header size
+	u16 pg_size;				//!< page size
+};
+
+/** 
+ * \struct uffs_NewBadBlockSt
+ * \brief holding new discovered bad block
+ */
+struct uffs_NewBadBlockSt {
+	u16 block;				//!< bad block, FIX ME to process more than one bad block
+};
+
+/**
+ * \struct uffs_FlashStatSt
+ * \typedef uffs_FlashStat
+ * \brief statistic data of flash read/write/erase activities
+ */
+typedef struct uffs_FlashStatSt {
+	int block_erase_count;
+	int page_write_count;
+	int page_read_count;
+	int page_header_read_count;
+	int spare_write_count;
+	int spare_read_count;
+} uffs_FlashStat;
+
+
+/** 
+ * \struct uffs_DeviceSt
+ * \brief The core data structure of UFFS, all information needed by manipulate UFFS object
+ * \note one partition corresponding one uffs device.
+ */
+struct uffs_DeviceSt {
+	URET (*Init)(uffs_Device *dev);				//!< low level initialization
+	URET (*Release)(uffs_Device *dev);			//!< low level release
+	void *_private;								//!< private data for device
+
+	struct uffs_StorageAttrSt		*attr;		//!< storage attribute
+	struct uffs_PartitionSt			par;		//!< partition information
+	struct uffs_FlashOpsSt			*ops;		//!< flash operations
+	struct uffs_BlockInfoCacheSt	bc;			//!< block info cache
+	struct uffs_LockSt				lock;		//!< lock data structure
+	struct uffs_PageBufDescSt		buf;		//!< page buffers
+	struct uffs_PageCommInfoSt		com;		//!< common information
+	struct uffs_TreeSt				tree;		//!< tree list of block
+	struct uffs_NewBadBlockSt		bad;		//!< new discovered bad block
+	struct uffs_FlashStatSt			st;			//!< statistic (counters)
+	struct uffs_memAllocatorSt		mem;		//!< uffs native memory allocator
+	u32	ref_count;								//!< device reference count
+	int	dev_num;								//!< device number (partition number)	
+};
+
+/** create the lock for uffs device */
+URET uffs_DeviceInitLock(uffs_Device *dev);
+
+/** delete the lock of uffs device */
+URET uffs_DeviceReleaseLock(uffs_Device *dev);
+
+/** lock uffs device */
+URET uffs_DeviceLock(uffs_Device *dev);
+
+/** unlock uffs device */
+URET uffs_DeviceUnLock(uffs_Device *dev);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 90 - 90
components/dfs/filesystems/uffs/src/inc/uffs/uffs_ecc.h

@@ -1,90 +1,90 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_ecc.h
- * \brief file handle operations
- * \author Ricky Zheng, created 8th Jun, 2005
- */
-
-#ifndef _UFFS_ECC_H_
-#define _UFFS_ECC_H_
-
-#include <string.h>
-
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-
-#define MAX_ECC_LENGTH	24	//!< 2K page ecc length is 24 bytes.
-
-/**
- * calculate ECC
- * \return length of generated ECC. (3 bytes ECC per 256 data) 
- */
-int uffs_EccMake(void *data, int data_len, void *ecc);
-
-/** 
- * correct data by ECC.
- *
- * return:   0 -- no error
- *			-1 -- can not be corrected
- *			>0 -- how many bits are corrected
- */
-int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc);
-
-
-/**
- * generate 12 bit ecc for maximum 8 bytes data
- */
-u16 uffs_EccMake8(void *data, int data_len);
-
-/**
- * correct maximum 8 bytes data from 12 bits ECC
- *
- * return:   0 -- no error
- *			-1 -- can not be corrected
- *			>0 -- how many bits are corrected
- */
-int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop);
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_ecc.h
+ * \brief file handle operations
+ * \author Ricky Zheng, created 8th Jun, 2005
+ */
+
+#ifndef _UFFS_ECC_H_
+#define _UFFS_ECC_H_
+
+#include <string.h>
+
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+
+#define MAX_ECC_LENGTH	24	//!< 2K page ecc length is 24 bytes.
+
+/**
+ * calculate ECC
+ * \return length of generated ECC. (3 bytes ECC per 256 data) 
+ */
+int uffs_EccMake(void *data, int data_len, void *ecc);
+
+/** 
+ * correct data by ECC.
+ *
+ * return:   0 -- no error
+ *			-1 -- can not be corrected
+ *			>0 -- how many bits are corrected
+ */
+int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc);
+
+
+/**
+ * generate 12 bit ecc for maximum 8 bytes data
+ */
+u16 uffs_EccMake8(void *data, int data_len);
+
+/**
+ * correct maximum 8 bytes data from 12 bits ECC
+ *
+ * return:   0 -- no error
+ *			-1 -- can not be corrected
+ *			>0 -- how many bits are corrected
+ */
+int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 152 - 150
components/dfs/filesystems/uffs/src/inc/uffs/uffs_fd.h

@@ -1,150 +1,152 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_fd.h
- * \brief PISIX like file operations
- * \author Ricky Zheng, created 8th Jun, 2005
- */
-
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs.h"
-#include "uffs/uffs_find.h"
-#include <string.h>
-
-/**
- * \brief definitions for uffs_stat::st_mode
- */
-#define	US_IFMT		0xF000	/* file type make */
-#define	US_IFREG	0x8000	/* regular */
-#define	US_IFLNK	0xA000	/* symbolic link */
-#define	US_IFDIR	0x4000	/* directory */
-#define	US_IREAD	00400	/* read permission */
-#define	US_IWRITE	00200	/* write permission */
-
-#define	US_IRWXU	00700	/* RWX	owner */
-#define	US_IRUSR	00400	/* R	owner */
-#define	US_IWUSR	00200	/* W	owner */
-#define	US_IXUSR	00100	/* X	owner */
-#define	US_IRWXG	00070	/* RWX	group */
-#define	US_IRGRP	00040	/* R	group */
-#define	US_IWGRP	00020	/* W	group */
-#define	US_IXGRP	00010	/* X	group */
-#define	US_IRWXO	00007	/* RWX	other */
-#define	US_IROTH	00004	/* R	other */
-#define	US_IWOTH	00002	/* W	other */
-#define	US_IXOTH	00001	/* X	other */
-
-/**
- * \brief POSIX dirent
- */
-struct uffs_dirent {
-    int d_ino;							/* inode number (serial number or this record) */
-	char d_name[MAX_FILENAME_LENGTH];	/* name of this record */
-
-    int d_off;							/* offset to this dirent */
-    unsigned short int d_reclen;		/* length of this uffs_dirent */
-    unsigned short int d_namelen;		/* length of this d_name */
-	unsigned char d_type;				/* type of this record */
-};
-
-/**
- * \brief POSIX DIR
- */
-typedef struct uffs_dirSt {
-    struct uffs_ObjectSt   *obj;		/* dir object */
-    struct uffs_FindInfoSt f;			/* find info */
-    struct uffs_ObjectInfoSt info;		/* object info */
-    struct uffs_dirent dirent;			/* dir entry */
-} uffs_DIR;
-
-/**
- * \brief POSIX stat
- */
-struct uffs_stat {
-    int			st_dev;     /* ID of device containing file */
-    int			st_ino;     /* inode number */
-    int			st_mode;    /* protection */
-    int			st_nlink;   /* number of hard links */
-    int			st_uid;     /* user ID of owner */
-    int			st_gid;     /* group ID of owner */
-    int			st_rdev;    /* device ID (if special file) */
-    long		st_size;    /* total size, in bytes */
-    int			st_blksize; /* blocksize for filesystem I/O */
-    int			st_blocks;  /* number of blocks allocated */
-    u32			st_atime;   /* time of last access */
-    u32			st_mtime;   /* time of last modification */
-    u32			st_ctime;   /* time of last status change */
-};
-
-
-URET uffs_InitDirEntryBuf(void);
-URET uffs_ReleaseDirEntryBuf(void);
-uffs_Pool * uffs_GetDirEntryBufPool(void);
-
-/* POSIX compliant file system APIs */
-
-int uffs_open(const char *name, int oflag, ...);
-int uffs_close(int fd);
-int uffs_read(int fd, void *data, int len);
-int uffs_write(int fd, void *data, int len);
-long uffs_seek(int fd, long offset, int origin);
-long uffs_tell(int fd);
-int uffs_eof(int fd);
-int uffs_flush(int fd);
-int uffs_rename(const char *old_name, const char *new_name);
-int uffs_remove(const char *name);
-int uffs_truncate(int fd, long remain);
-
-int uffs_mkdir(const char *name, ...);
-int uffs_rmdir(const char *name);
-
-int uffs_stat(const char *name, struct uffs_stat *buf);
-int uffs_lstat(const char *name, struct uffs_stat *buf);
-int uffs_fstat(int fd, struct uffs_stat *buf);
-
-int uffs_closedir(uffs_DIR *dirp);
-uffs_DIR * uffs_opendir(const char *path);
-struct uffs_dirent * uffs_readdir(uffs_DIR *dirp);
-
-void uffs_rewinddir(uffs_DIR *dirp);
-
-#if 0
-void uffs_seekdir(uffs_DIR *dirp, long loc);
-long uffs_telldir(uffs_DIR *dirp);
-#endif
-
-int uffs_get_error(void);
-int uffs_set_error(int err);
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fd.h
+ * \brief PISIX like file operations
+ * \author Ricky Zheng, created 8th Jun, 2005
+ */
+
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs.h"
+#include "uffs/uffs_find.h"
+#include <string.h>
+
+/**
+ * \brief definitions for uffs_stat::st_mode
+ */
+#define	US_IFMT		0xF000	/* file type make */
+#define	US_IFREG	0x8000	/* regular */
+#define	US_IFLNK	0xA000	/* symbolic link */
+#define	US_IFDIR	0x4000	/* directory */
+#define	US_IREAD	00400	/* read permission */
+#define	US_IWRITE	00200	/* write permission */
+
+#define	US_IRWXU	00700	/* RWX	owner */
+#define	US_IRUSR	00400	/* R	owner */
+#define	US_IWUSR	00200	/* W	owner */
+#define	US_IXUSR	00100	/* X	owner */
+#define	US_IRWXG	00070	/* RWX	group */
+#define	US_IRGRP	00040	/* R	group */
+#define	US_IWGRP	00020	/* W	group */
+#define	US_IXGRP	00010	/* X	group */
+#define	US_IRWXO	00007	/* RWX	other */
+#define	US_IROTH	00004	/* R	other */
+#define	US_IWOTH	00002	/* W	other */
+#define	US_IXOTH	00001	/* X	other */
+
+/**
+ * \brief POSIX dirent
+ */
+struct uffs_dirent 
+{
+    int 	d_ino;						/* inode number (serial number or this record) */
+	char 	d_name[MAX_FILENAME_LENGTH];	/* name of this record */
+    int 	d_off;						/* offset to this dirent */
+    u16 	d_reclen;						/* length of this uffs_dirent */
+    u16 	d_namelen;						/* length of this d_name */
+	u32 	d_type;							/* type of this record ,ÒªÓëinfo.attrµÄÀàÐͱ£³ÖÒ»ÖÂ*/
+};
+
+/**
+ * \brief POSIX DIR
+ */
+typedef struct uffs_dirSt 
+{
+    struct uffs_ObjectSt   	*obj;		/* dir object */
+    struct uffs_FindInfoSt	f;		/* find info */
+    struct uffs_ObjectInfoSt	info;		/* object info */
+    struct uffs_dirent 	dirent;	/* dir entry */
+}uffs_DIR;
+
+/**
+ * \brief POSIX stat
+ */
+struct uffs_stat 
+{
+    int				st_dev;     /* ID of device containing file */
+    int				st_ino;     /* inode number */
+    int				st_mode;    /* protection */
+    int				st_nlink;   /* number of hard links */
+    int				st_uid;     /* user ID of owner */
+    int				st_gid;     /* group ID of owner */
+    int				st_rdev;    /* device ID (if special file) */
+    long			st_size;    /* total size, in bytes */
+    int				st_blksize; /* blocksize for filesystem I/O */
+    int				st_blocks;  /* number of blocks allocated */
+    u32		st_atime;   /* time of last access */
+    u32		st_mtime;   /* time of last modification */
+    u32		st_ctime;   /* time of last status change */
+};
+
+
+int uffs_InitDirEntryBuf(void);
+int uffs_ReleaseDirEntryBuf(void);
+uffs_Pool * uffs_GetDirEntryBufPool(void);
+
+/* POSIX compliant file system APIs */
+
+int uffs_open(const char *name, int oflag, ...);
+int uffs_close(int fd);
+int uffs_read(int fd, void *data, int len);
+int uffs_write(int fd, void *data, int len);
+long uffs_seek(int fd, long offset, int origin);
+long uffs_tell(int fd);
+int uffs_eof(int fd);
+int uffs_flush(int fd);
+int uffs_rename(const char *old_name, const char *new_name);
+int uffs_remove(const char *name);
+int uffs_truncate(int fd, long remain);
+
+int uffs_mkdir(const char *name, ...);
+int uffs_rmdir(const char *name);
+
+int uffs_stat(const char *name, struct uffs_stat *buf);
+int uffs_lstat(const char *name, struct uffs_stat *buf);
+int uffs_fstat(int fd, struct uffs_stat *buf);
+
+int uffs_closedir(uffs_DIR *dirp);
+uffs_DIR * uffs_opendir(const char *path);
+struct uffs_dirent * uffs_readdir(uffs_DIR *dirp);
+
+void uffs_rewinddir(uffs_DIR *dirp);
+
+#if 0
+void uffs_seekdir(uffs_DIR *dirp, long loc);
+long uffs_telldir(uffs_DIR *dirp);
+#endif
+
+int uffs_get_error(void);
+int uffs_set_error(int err);
+

+ 74 - 74
components/dfs/filesystems/uffs/src/inc/uffs/uffs_find.h

@@ -1,74 +1,74 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_find.h
- * \brief find objects under dir
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_FIND_H_
-#define _UFFS_FIND_H_
-
-#include "uffs/uffs_fs.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-typedef struct uffs_FindInfoSt {
-	uffs_Device *dev;				//!< the device to be searched
-	u16 serial;						//!< the dir serial number
-	int step;						//!< step: 0 - working on dir entries, 1 - working on file entries, 2 - stoped.
-	int hash;						//!< hash entry, internal used
-	TreeNode *work;					//!< working node, internal used.
-	int pos;						//!< current position
-} uffs_FindInfo;
-
-
-URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err);
-URET uffs_FindObjectOpen(uffs_FindInfo *find_handle, uffs_Object *dir);
-URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir);
-URET uffs_FindObjectFirst(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
-URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
-URET uffs_FindObjectRewind(uffs_FindInfo *find_handle);
-URET uffs_FindObjectClose(uffs_FindInfo * find_handle);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_find.h
+ * \brief find objects under dir
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_FIND_H_
+#define _UFFS_FIND_H_
+
+#include "uffs/uffs_fs.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+typedef struct uffs_FindInfoSt {
+	uffs_Device *dev;				//!< the device to be searched
+	u16 serial;						//!< the dir serial number
+	int step;						//!< step: 0 - working on dir entries, 1 - working on file entries, 2 - stoped.
+	int hash;						//!< hash entry, internal used
+	TreeNode *work;					//!< working node, internal used.
+	int pos;						//!< current position
+} uffs_FindInfo;
+
+
+URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err);
+URET uffs_FindObjectOpen(uffs_FindInfo *find_handle, uffs_Object *dir);
+URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir);
+URET uffs_FindObjectFirst(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
+URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
+URET uffs_FindObjectRewind(uffs_FindInfo *find_handle);
+URET uffs_FindObjectClose(uffs_FindInfo * find_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+

+ 274 - 274
components/dfs/filesystems/uffs/src/inc/uffs/uffs_flash.h

@@ -1,274 +1,274 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_public.h
- * \brief flash interface for UFFS
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_FLASH_H_
-#define _UFFS_FLASH_H_
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs_device.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-/** ECC options (uffs_StorageAttrSt.ecc_opt) */
-#define UFFS_ECC_NONE		0	//!< do not use ECC
-#define UFFS_ECC_SOFT		1	//!< UFFS calculate the ECC
-#define UFFS_ECC_HW			2	//!< Flash driver(or by hardware) calculate the ECC
-#define UFFS_ECC_HW_AUTO	3	//!< Hardware calculate the ECC and automatically write to spare.
-
-
-/** spare layout options (uffs_StorageAttrSt.layout_opt) */
-#define UFFS_LAYOUT_UFFS	0	//!< do layout by dev->attr information
-#define UFFS_LAYOUT_FLASH	1	//!< flash driver do the layout
-
-#define UFFS_SPARE_LAYOUT_SIZE	6	//!< maximum spare layout array size, 2 segments
-
-/** flash operation return code */
-#define UFFS_FLASH_NO_ERR		0		//!< no error
-#define UFFS_FLASH_ECC_OK		1		//!< bit-flip found, but corrected by ECC
-#define UFFS_FLASH_IO_ERR		-1		//!< I/O error
-#define UFFS_FLASH_ECC_FAIL		-2		//!< ECC failed
-#define UFFS_FLASH_BAD_BLK		-3		//!< bad block
-#define UFFS_FLASH_UNKNOWN_ERR	-100	//!< unkown error?
-
-#define UFFS_FLASH_HAVE_ERR(e)		((e) < 0)
-
-#if defined(CONFIG_BAD_BLOCK_POLICY_STRICT)
-# define UFFS_FLASH_IS_BAD_BLOCK(e)	((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_ECC_OK || (e) == UFFS_FLASH_BAD_BLK)
-#else
-# define UFFS_FLASH_IS_BAD_BLOCK(e)	((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_BAD_BLK)
-#endif
-
-
-/** defines for page info (data length and data sum) */
-#define UFFS_PAGE_INFO_CLEAN	0xFFFFFFFF
-#define UFFS_PAGE_INFO_IOERR	0xDEADFFFF
-#define UFFS_PAGE_GET_LEN(info)	(info & 0xFFFF)
-#define UFFS_PAGE_GET_DSUM(info) (info >> 16)
-#define UFFS_PAGE_MAKE_INFO(d_len, d_sum) ((d_sum << 16) | d_len)
-
-/** 
- * \struct uffs_StorageAttrSt
- * \brief uffs device storage attribute, provide by nand specific file
- */
-struct uffs_StorageAttrSt {
-	u32 total_blocks;		//!< total blocks in this chip
-	u16 page_data_size;		//!< page data size (physical page data size, e.g. 512)
-	u16 pages_per_block;	//!< pages per block
-	u8 spare_size;			//!< page spare size (physical page spare size, e.g. 16)
-	u8 block_status_offs;	//!< block status byte offset in spare
-	int ecc_opt;			//!< ecc option ( #UFFS_ECC_[NONE|SOFT|HW|HW_AUTO] )
-	int layout_opt;			//!< layout option (#UFFS_LAYOUT_UFFS or #UFFS_LAYOUT_FLASH)
-	const u8 *ecc_layout;	//!< page data ECC layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
-	const u8 *data_layout;	//!< spare data layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
-	u8 _uffs_ecc_layout[UFFS_SPARE_LAYOUT_SIZE];	//!< uffs spare ecc layout
-	u8 _uffs_data_layout[UFFS_SPARE_LAYOUT_SIZE];	//!< uffs spare data layout
-	void *_private;			//!< private data for storage attribute
-};
-
-
-/**
- * \struct uffs_FlashOpsSt 
- * \brief low level flash operations, should be implement in flash driver
- */
-struct uffs_FlashOpsSt {
-	/**
-	 * Read page data.
-	 * 
-	 * if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return ecc (if ecc != NULL).
-	 *
-	 * if ecc_opt is UFFS_ECC_HW_AUTO, flash driver do ecc correction aganist ecc in spare area.
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *			#UFFS_FLASH_ECC_FAIL: page data has flip bits and ecc correct failed.
-	 *			#UFFS_FLASH_ECC_OK: page data has flip bits and corrected by ecc.
-	 *
-	 * \note pad 0xFF for calculating ECC if len < page_data_size
-	 */
-	int (*ReadPageData)(uffs_Device *dev, u32 block, u32 page, u8 *data, int len, u8 *ecc);
-
-
-	/**
-	 * Read page spare [len] bytes from [ofs].
-	 *
-	 * \note flash driver must privide this function.
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *
-	 * \note flash driver DO NOT need to do ecc correction for spare data,
-	 *		UFFS will take care of spare data ecc.
-	 */
-	int (*ReadPageSpare)(uffs_Device *dev, u32 block, u32 page, u8 *spare, int ofs, int len);
-
-	/**
-	 * Read page spare, unload to tag and ecc.
-	 *
-	 * \note flash driver must provide this function if layout_opt is UFFS_LAYOUT_FLASH.
-	 *       UFFS will use this function (if exist) prio to 'ReadPageSpare()'
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *
-	 * \note flash driver DO NOT need to do ecc correction for spare data,
-	 *		UFFS will take care of spare data ecc.
-	 */
-	int (*ReadPageSpareWithLayout)(uffs_Device *dev, u32 block, u32 page, u8 *tag, int len, u8 *ecc);
-
-	/**
-	 * Write page data.
-	 *
-	 * if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return the ecc.
-	 * if ecc_opt is UFFS_ECC_HW_AUTO, do not need to return ecc.
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
-	 *
-	 * \note pad 0xFF for calculating ECC if len < page_data_size
-	 */
-	int (*WritePageData)(uffs_Device *dev, u32 block, u32 page, const u8 *data, int len, u8 *ecc);
-
-
-	/**
-	 * Write [len] bytes to page spare from [ofs].
-	 *
-	 * \note flash driver must privide this function.
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
-	 */
-	int (*WritePageSpare)(uffs_Device *dev, u32 block, u32 page, const u8 *spare, int ofs, int len, UBOOL eod);
-	
-	/**
-	 * Write full page, include page data and spare.
-	 *
-	 * you need to pack spare within nand driver.
-	 *
-	 * \note if layout_opt is UFFS_LAYOUT_FLASH, flash driver must implement this function.
-	 *       UFFS will use this function (if provided) prio to 'WritePageData() + WritePageSpare()'
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
-	 */
-	int (*WriteFullPage)(uffs_Device *dev, u32 block, u32 page, const u8* data, int len, const u8 *ts, int ts_len, const u8 *ecc);
-
-	/**
-	 * check block status.
-	 *
-	 * \note flash driver may maintain a bad block table to speed up bad block checking or
-	 *		it will require one or two read spare I/O to check block status.
-	 *
-	 * \note if this function is not provided, UFFS check the block_status byte in spare.
-	 *
-	 * \return 1 if it's a bad block, 0 if it's not.
-	 */
-	int (*IsBadBlock)(uffs_Device *dev, u32 block);
-
-	/**
-	 * Mark a new bad block.
-	 *
-	 * \return 0 if success, otherwise return -1.
-	 */
-	int (*MarkBadBlock)(uffs_Device *dev, u32 block);
-
-	/**
-	 * Erase a block.
-	 *
-	 * \return	#UFFS_FLASH_NO_ERR: success
-	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
-	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
-	 */
-	int (*EraseBlock)(uffs_Device *dev, u32 block);
-};
-
-/** make spare from tag store and ecc */
-void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare);
-
-/** read page spare, fill tag and ECC */
-int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc);
-
-/** read page data to page buf and do ECC correct */
-int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf);
-
-/** write page data and spare */
-int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag);
-
-/** Mark this block as bad block */
-int uffs_FlashMarkBadBlock(uffs_Device *dev, int block);
-
-/** Is this block a bad block ? */
-UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block);
-
-/** Erase flash block */
-int uffs_FlashEraseBlock(uffs_Device *dev, int block);
-
-/* mark a clean page as 'dirty' (and 'invalid') */
-int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page);
-
-/**
- * get page head info
- *
- * \return #UFFS_PAGE_INFO_IOERR if I/O error, otherwise return page info
- */
-u32 uffs_FlashGetPageInfo(uffs_Device *dev, int block, int page);
-
-/** load uffs_FileInfo from flash storage */
-URET uffs_FlashReadFileinfoPhy(uffs_Device *dev, int block, int page, uffs_FileInfo *info);
-
-/**
- * Initialize UFFS flash interface
- */
-URET uffs_FlashInterfaceInit(uffs_Device *dev);
-
-/**
- * Release UFFS flash interface
- */
-URET uffs_FlashInterfaceRelease(uffs_Device *dev);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_public.h
+ * \brief flash interface for UFFS
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_FLASH_H_
+#define _UFFS_FLASH_H_
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_device.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/** ECC options (uffs_StorageAttrSt.ecc_opt) */
+#define UFFS_ECC_NONE		0	//!< do not use ECC
+#define UFFS_ECC_SOFT		1	//!< UFFS calculate the ECC
+#define UFFS_ECC_HW			2	//!< Flash driver(or by hardware) calculate the ECC
+#define UFFS_ECC_HW_AUTO	3	//!< Hardware calculate the ECC and automatically write to spare.
+
+
+/** spare layout options (uffs_StorageAttrSt.layout_opt) */
+#define UFFS_LAYOUT_UFFS	0	//!< do layout by dev->attr information
+#define UFFS_LAYOUT_FLASH	1	//!< flash driver do the layout
+
+#define UFFS_SPARE_LAYOUT_SIZE	6	//!< maximum spare layout array size, 2 segments
+
+/** flash operation return code */
+#define UFFS_FLASH_NO_ERR		0		//!< no error
+#define UFFS_FLASH_ECC_OK		1		//!< bit-flip found, but corrected by ECC
+#define UFFS_FLASH_IO_ERR		-1		//!< I/O error
+#define UFFS_FLASH_ECC_FAIL		-2		//!< ECC failed
+#define UFFS_FLASH_BAD_BLK		-3		//!< bad block
+#define UFFS_FLASH_UNKNOWN_ERR	-100	//!< unkown error?
+
+#define UFFS_FLASH_HAVE_ERR(e)		((e) < 0)
+
+#if defined(CONFIG_BAD_BLOCK_POLICY_STRICT)
+# define UFFS_FLASH_IS_BAD_BLOCK(e)	((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_ECC_OK || (e) == UFFS_FLASH_BAD_BLK)
+#else
+# define UFFS_FLASH_IS_BAD_BLOCK(e)	((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_BAD_BLK)
+#endif
+
+
+/** defines for page info (data length and data sum) */
+#define UFFS_PAGE_INFO_CLEAN	0xFFFFFFFF
+#define UFFS_PAGE_INFO_IOERR	0xDEADFFFF
+#define UFFS_PAGE_GET_LEN(info)	(info & 0xFFFF)
+#define UFFS_PAGE_GET_DSUM(info) (info >> 16)
+#define UFFS_PAGE_MAKE_INFO(d_len, d_sum) ((d_sum << 16) | d_len)
+
+/** 
+ * \struct uffs_StorageAttrSt
+ * \brief uffs device storage attribute, provide by nand specific file
+ */
+struct uffs_StorageAttrSt {
+	u32 total_blocks;		//!< total blocks in this chip
+	u16 page_data_size;		//!< page data size (physical page data size, e.g. 512)
+	u16 pages_per_block;	//!< pages per block
+	u8 spare_size;			//!< page spare size (physical page spare size, e.g. 16)
+	u8 block_status_offs;	//!< block status byte offset in spare
+	int ecc_opt;			//!< ecc option ( #UFFS_ECC_[NONE|SOFT|HW|HW_AUTO] )
+	int layout_opt;			//!< layout option (#UFFS_LAYOUT_UFFS or #UFFS_LAYOUT_FLASH)
+	const u8 *ecc_layout;	//!< page data ECC layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
+	const u8 *data_layout;	//!< spare data layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
+	u8 _uffs_ecc_layout[UFFS_SPARE_LAYOUT_SIZE];	//!< uffs spare ecc layout
+	u8 _uffs_data_layout[UFFS_SPARE_LAYOUT_SIZE];	//!< uffs spare data layout
+	void *_private;			//!< private data for storage attribute
+};
+
+
+/**
+ * \struct uffs_FlashOpsSt 
+ * \brief low level flash operations, should be implement in flash driver
+ */
+struct uffs_FlashOpsSt {
+	/**
+	 * Read page data.
+	 * 
+	 * if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return ecc (if ecc != NULL).
+	 *
+	 * if ecc_opt is UFFS_ECC_HW_AUTO, flash driver do ecc correction aganist ecc in spare area.
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *			#UFFS_FLASH_ECC_FAIL: page data has flip bits and ecc correct failed.
+	 *			#UFFS_FLASH_ECC_OK: page data has flip bits and corrected by ecc.
+	 *
+	 * \note pad 0xFF for calculating ECC if len < page_data_size
+	 */
+	int (*ReadPageData)(uffs_Device *dev, u32 block, u32 page, u8 *data, int len, u8 *ecc);
+
+
+	/**
+	 * Read page spare [len] bytes from [ofs].
+	 *
+	 * \note flash driver must privide this function.
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *
+	 * \note flash driver DO NOT need to do ecc correction for spare data,
+	 *		UFFS will take care of spare data ecc.
+	 */
+	int (*ReadPageSpare)(uffs_Device *dev, u32 block, u32 page, u8 *spare, int ofs, int len);
+
+	/**
+	 * Read page spare, unload to tag and ecc.
+	 *
+	 * \note flash driver must provide this function if layout_opt is UFFS_LAYOUT_FLASH.
+	 *       UFFS will use this function (if exist) prio to 'ReadPageSpare()'
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *
+	 * \note flash driver DO NOT need to do ecc correction for spare data,
+	 *		UFFS will take care of spare data ecc.
+	 */
+	int (*ReadPageSpareWithLayout)(uffs_Device *dev, u32 block, u32 page, u8 *tag, int len, u8 *ecc);
+
+	/**
+	 * Write page data.
+	 *
+	 * if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return the ecc.
+	 * if ecc_opt is UFFS_ECC_HW_AUTO, do not need to return ecc.
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
+	 *
+	 * \note pad 0xFF for calculating ECC if len < page_data_size
+	 */
+	int (*WritePageData)(uffs_Device *dev, u32 block, u32 page, const u8 *data, int len, u8 *ecc);
+
+
+	/**
+	 * Write [len] bytes to page spare from [ofs].
+	 *
+	 * \note flash driver must privide this function.
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
+	 */
+	int (*WritePageSpare)(uffs_Device *dev, u32 block, u32 page, const u8 *spare, int ofs, int len, UBOOL eod);
+	
+	/**
+	 * Write full page, include page data and spare.
+	 *
+	 * you need to pack spare within nand driver.
+	 *
+	 * \note if layout_opt is UFFS_LAYOUT_FLASH, flash driver must implement this function.
+	 *       UFFS will use this function (if provided) prio to 'WritePageData() + WritePageSpare()'
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
+	 */
+	int (*WriteFullPage)(uffs_Device *dev, u32 block, u32 page, const u8* data, int len, const u8 *ts, int ts_len, const u8 *ecc);
+
+	/**
+	 * check block status.
+	 *
+	 * \note flash driver may maintain a bad block table to speed up bad block checking or
+	 *		it will require one or two read spare I/O to check block status.
+	 *
+	 * \note if this function is not provided, UFFS check the block_status byte in spare.
+	 *
+	 * \return 1 if it's a bad block, 0 if it's not.
+	 */
+	int (*IsBadBlock)(uffs_Device *dev, u32 block);
+
+	/**
+	 * Mark a new bad block.
+	 *
+	 * \return 0 if success, otherwise return -1.
+	 */
+	int (*MarkBadBlock)(uffs_Device *dev, u32 block);
+
+	/**
+	 * Erase a block.
+	 *
+	 * \return	#UFFS_FLASH_NO_ERR: success
+	 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+	 *			#UFFS_FLASH_BAD_BLK: a bad block detected.
+	 */
+	int (*EraseBlock)(uffs_Device *dev, u32 block);
+};
+
+/** make spare from tag store and ecc */
+void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare);
+
+/** read page spare, fill tag and ECC */
+int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc);
+
+/** read page data to page buf and do ECC correct */
+int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf);
+
+/** write page data and spare */
+int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag);
+
+/** Mark this block as bad block */
+int uffs_FlashMarkBadBlock(uffs_Device *dev, int block);
+
+/** Is this block a bad block ? */
+UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block);
+
+/** Erase flash block */
+int uffs_FlashEraseBlock(uffs_Device *dev, int block);
+
+/* mark a clean page as 'dirty' (and 'invalid') */
+int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page);
+
+/**
+ * get page head info
+ *
+ * \return #UFFS_PAGE_INFO_IOERR if I/O error, otherwise return page info
+ */
+u32 uffs_FlashGetPageInfo(uffs_Device *dev, int block, int page);
+
+/** load uffs_FileInfo from flash storage */
+URET uffs_FlashReadFileinfoPhy(uffs_Device *dev, int block, int page, uffs_FileInfo *info);
+
+/**
+ * Initialize UFFS flash interface
+ */
+URET uffs_FlashInterfaceInit(uffs_Device *dev);
+
+/**
+ * Release UFFS flash interface
+ */
+URET uffs_FlashInterfaceRelease(uffs_Device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 137 - 137
components/dfs/filesystems/uffs/src/inc/uffs/uffs_fs.h

@@ -1,137 +1,137 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_fs.h
- * \brief uffs basic file operations
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_FS_H_
-#define _UFFS_FS_H_
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-/** file object */
-struct uffs_ObjectSt {
-	/******* objects manager ********/
-	int dev_lock_count;
-	int dev_get_count;
-
-	/******** init level 0 ********/
-	const char * name;					//!< pointer to the start of name, for open or create
-	u32 name_len;						//!< name length
-	u16 sum;							//!< sum of name
-	uffs_Device *dev;					//!< uffs device
-	u32 oflag;
-	u8 type;
-	u16 head_pages;						//!< data pages on file head block
-	u16 parent;
-
-	/******* init level 1 ********/
-	TreeNode *node;						//!< file entry node in tree
-	u16 serial;
-	
-	/******* output ******/
-	int err;							//!< error number
-
-	/******* current *******/
-	u32 pos;							//!< current position in file
-
-	/***** others *******/
-	UBOOL attr_loaded;					//!< attributes loaded ?
-	UBOOL open_succ;					//!< U_TRUE or U_FALSE
-
-};
-
-typedef struct uffs_ObjectSt uffs_Object;
-
-
-
-#define uffs_GetObjectErr(obj) ((obj)->err)
-#define uffs_ClearObjectErr(obj) do { (obj)->err = UENOERR; } while (0)
-
-uffs_Pool * uffs_GetObjectPool(void);
-
-URET uffs_InitObjectBuf(void);
-URET uffs_ReleaseObjectBuf(void);
-uffs_Object * uffs_GetObject(void);
-void uffs_PutObject(uffs_Object *obj);
-int uffs_GetObjectIndex(uffs_Object *obj);
-uffs_Object * uffs_GetObjectByIndex(int idx);
-
-
-/**
- * Re-initialize an object.
- * should call this function if you want to re-use an object.
- */
-URET uffs_ReInitObject(uffs_Object *obj);
-
-URET uffs_ParseObject(uffs_Object *obj, const char *name);
-
-URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev, 
-								   int dir, const char *name, int name_len, int oflag);
-URET uffs_OpenObjectEx(uffs_Object *obj, uffs_Device *dev, 
-								   int dir, const char *name, int name_len, int oflag);
-
-URET uffs_OpenObject(uffs_Object *obj, const char *fullname, int oflag);
-URET uffs_TruncateObject(uffs_Object *obj, u32 remain);
-URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag);
-
-URET uffs_CloseObject(uffs_Object *obj);
-int uffs_WriteObject(uffs_Object *obj, const void *data, int len);
-int uffs_ReadObject(uffs_Object *obj, void *data, int len);
-long uffs_SeekObject(uffs_Object *obj, long offset, int origin);
-int uffs_GetCurOffset(uffs_Object *obj);
-int uffs_EndOfFile(uffs_Object *obj);
-URET uffs_FlushObject(uffs_Object *obj);
-
-URET uffs_RenameObject(const char *old_name, const char *new_name, int *err);
-URET uffs_DeleteObject(const char * name, int *err);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_fs.h
+ * \brief uffs basic file operations
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_FS_H_
+#define _UFFS_FS_H_
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/** file object */
+struct uffs_ObjectSt {
+	/******* objects manager ********/
+	int dev_lock_count;
+	int dev_get_count;
+
+	/******** init level 0 ********/
+	const char * name;					//!< pointer to the start of name, for open or create
+	u32 name_len;						//!< name length
+	u16 sum;							//!< sum of name
+	uffs_Device *dev;					//!< uffs device
+	u32 oflag;
+	u8 type;
+	u16 head_pages;						//!< data pages on file head block
+	u16 parent;
+
+	/******* init level 1 ********/
+	TreeNode *node;						//!< file entry node in tree
+	u16 serial;
+	
+	/******* output ******/
+	int err;							//!< error number
+
+	/******* current *******/
+	u32 pos;							//!< current position in file
+
+	/***** others *******/
+	UBOOL attr_loaded;					//!< attributes loaded ?
+	UBOOL open_succ;					//!< U_TRUE or U_FALSE
+
+};
+
+typedef struct uffs_ObjectSt uffs_Object;
+
+
+
+#define uffs_GetObjectErr(obj) ((obj)->err)
+#define uffs_ClearObjectErr(obj) do { (obj)->err = UENOERR; } while (0)
+
+uffs_Pool * uffs_GetObjectPool(void);
+
+URET uffs_InitObjectBuf(void);
+URET uffs_ReleaseObjectBuf(void);
+uffs_Object * uffs_GetObject(void);
+void uffs_PutObject(uffs_Object *obj);
+int uffs_GetObjectIndex(uffs_Object *obj);
+uffs_Object * uffs_GetObjectByIndex(int idx);
+
+
+/**
+ * Re-initialize an object.
+ * should call this function if you want to re-use an object.
+ */
+URET uffs_ReInitObject(uffs_Object *obj);
+
+URET uffs_ParseObject(uffs_Object *obj, const char *name);
+
+URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev, 
+								   int dir, const char *name, int name_len, int oflag);
+URET uffs_OpenObjectEx(uffs_Object *obj, uffs_Device *dev, 
+								   int dir, const char *name, int name_len, int oflag);
+
+URET uffs_OpenObject(uffs_Object *obj, const char *fullname, int oflag);
+URET uffs_TruncateObject(uffs_Object *obj, u32 remain);
+URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag);
+
+URET uffs_CloseObject(uffs_Object *obj);
+int uffs_WriteObject(uffs_Object *obj, const void *data, int len);
+int uffs_ReadObject(uffs_Object *obj, void *data, int len);
+long uffs_SeekObject(uffs_Object *obj, long offset, int origin);
+int uffs_GetCurOffset(uffs_Object *obj);
+int uffs_EndOfFile(uffs_Object *obj);
+URET uffs_FlushObject(uffs_Object *obj);
+
+URET uffs_RenameObject(const char *old_name, const char *new_name, int *err);
+URET uffs_DeleteObject(const char * name, int *err);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 130 - 130
components/dfs/filesystems/uffs/src/inc/uffs/uffs_mem.h

@@ -1,130 +1,130 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef UFFS_MEM_H
-#define UFFS_MEM_H
-
-#include "uffs/uffs_device.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-#define MAX_ECC_SIZE	(3 * UFFS_MAX_PAGE_SIZE / 256)
-#define MAX_SPARE_SIZE	(8 * UFFS_MAX_PAGE_SIZE / 256)
-#define MAX_SPARE_BUF	10
-
-
-#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
-
-#define HEAP_HASH_BIT	6							/* hash table bit */
-#define HEAP_HASH_SIZE (1 << (HEAP_HASH_BIT - 1))	/* hash table size */
-#define HEAP_HASH_MASK	(HEAP_HASH_SIZE - 1)		/* hash table mask */
-#define GET_HASH_INDEX(p) ((((unsigned long)(p)) >> 2) & HEAP_HASH_MASK)
-
-/* memory alloc node  */
-typedef struct HeapManagementNodeSt{
-	int task_id;					/* who alloc this block? it's the caller's task id */
-	struct HeapManagementNodeSt * next;	/* point to next node */
-	void *p;						/* point to allocated block */
-	int size;						/* block size */
-} HeapMm;
-
-typedef HeapMm* HeapHashTable;
-
-/** \note: uffs_MemInitHeap should be called before using native memory allocator on each device */
-void uffs_MemInitHeap(void *addr, int size);
-
-URET uffs_MemInitNativeAllocator(uffs_Device *dev);
-int uffs_MemReleaseNativeAllocator(uffs_Device *dev);
-
-#endif //CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
-
-
-/** uffs native memory allocator */
-typedef struct uffs_memAllocatorSt {
-	URET (*init)(struct uffs_DeviceSt *dev);			/* init memory allocator, setup buffer sizes */
-	URET (*release)(struct uffs_DeviceSt *dev);			/* release memory allocator (for dynamic memory allocation) */
-	
-	void * (*malloc)(struct uffs_DeviceSt *dev, unsigned int size); /* allocate memory (for dynamic memory allocation) */
-	URET (*free)(struct uffs_DeviceSt *dev, void *p);   /* free memory (for dynamic memory allocation) */
-
-	void * blockinfo_pool_buf;				//!< block info cache buffers
-	void * pagebuf_pool_buf;				//!< page buffers
-	void * tree_nodes_pool_buf;				//!< tree nodes buffer
-	void * spare_pool_buf;					//!< spare buffers
-
-	int blockinfo_pool_size;			//!< block info cache buffers size
-	int pagebuf_pool_size;				//!< page buffers size
-	int tree_nodes_pool_size;			//!< tree nodes buffer size
-	int spare_pool_size;				//!< spare buffer pool size
-
-	uffs_Pool tree_pool;
-	uffs_Pool spare_pool;
-
-	int spare_data_size;				//!< spare data size, calculated by UFFS.
-
-
-#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
-	HeapHashTable tbl[HEAP_HASH_SIZE];
-	int count;
-	int maxused;
-#endif
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
-	char *buf_start;
-	int buf_size;
-	int pos;
-#endif
-
-} uffs_MemAllocator;
-
-
-#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
-void uffs_MemSetupNativeAllocator(uffs_MemAllocator *allocator);
-#endif
-
-#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
-void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator);
-#endif
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
-void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef UFFS_MEM_H
+#define UFFS_MEM_H
+
+#include "uffs/uffs_device.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#define MAX_ECC_SIZE	(3 * UFFS_MAX_PAGE_SIZE / 256)
+#define MAX_SPARE_SIZE	(8 * UFFS_MAX_PAGE_SIZE / 256)
+#define MAX_SPARE_BUF	10
+
+
+#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
+
+#define HEAP_HASH_BIT	6							/* hash table bit */
+#define HEAP_HASH_SIZE (1 << (HEAP_HASH_BIT - 1))	/* hash table size */
+#define HEAP_HASH_MASK	(HEAP_HASH_SIZE - 1)		/* hash table mask */
+#define GET_HASH_INDEX(p) ((((unsigned long)(p)) >> 2) & HEAP_HASH_MASK)
+
+/* memory alloc node  */
+typedef struct HeapManagementNodeSt{
+	int task_id;					/* who alloc this block? it's the caller's task id */
+	struct HeapManagementNodeSt * next;	/* point to next node */
+	void *p;						/* point to allocated block */
+	int size;						/* block size */
+} HeapMm;
+
+typedef HeapMm* HeapHashTable;
+
+/** \note: uffs_MemInitHeap should be called before using native memory allocator on each device */
+void uffs_MemInitHeap(void *addr, int size);
+
+URET uffs_MemInitNativeAllocator(uffs_Device *dev);
+int uffs_MemReleaseNativeAllocator(uffs_Device *dev);
+
+#endif //CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
+
+
+/** uffs native memory allocator */
+typedef struct uffs_memAllocatorSt {
+	URET (*init)(struct uffs_DeviceSt *dev);			/* init memory allocator, setup buffer sizes */
+	URET (*release)(struct uffs_DeviceSt *dev);			/* release memory allocator (for dynamic memory allocation) */
+	
+	void * (*malloc)(struct uffs_DeviceSt *dev, unsigned int size); /* allocate memory (for dynamic memory allocation) */
+	URET (*free)(struct uffs_DeviceSt *dev, void *p);   /* free memory (for dynamic memory allocation) */
+
+	void * blockinfo_pool_buf;				//!< block info cache buffers
+	void * pagebuf_pool_buf;				//!< page buffers
+	void * tree_nodes_pool_buf;				//!< tree nodes buffer
+	void * spare_pool_buf;					//!< spare buffers
+
+	int blockinfo_pool_size;			//!< block info cache buffers size
+	int pagebuf_pool_size;				//!< page buffers size
+	int tree_nodes_pool_size;			//!< tree nodes buffer size
+	int spare_pool_size;				//!< spare buffer pool size
+
+	uffs_Pool tree_pool;
+	uffs_Pool spare_pool;
+
+	int spare_data_size;				//!< spare data size, calculated by UFFS.
+
+
+#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
+	HeapHashTable tbl[HEAP_HASH_SIZE];
+	int count;
+	int maxused;
+#endif
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
+	char *buf_start;
+	int buf_size;
+	int pos;
+#endif
+
+} uffs_MemAllocator;
+
+
+#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
+void uffs_MemSetupNativeAllocator(uffs_MemAllocator *allocator);
+#endif
+
+#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
+void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator);
+#endif
+
+#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
+void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 90 - 90
components/dfs/filesystems/uffs/src/inc/uffs/uffs_mtb.h

@@ -1,90 +1,90 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_mtb.h
- * \brief mount table related stuff
- * \author Ricky Zheng
- */
-
-#ifndef UFFS_MTB_H
-#define UFFS_MTB_H
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-typedef struct uffs_MountTableEntrySt {
-	uffs_Device *dev;
-	int start_block;
-	int end_block;
-	const char *mount;
-	struct uffs_MountTableEntrySt *next;
-} uffs_MountTable;
-
-/** initialize registered mount table */
-URET uffs_InitMountTable(void);									
-
-/** release registered mount table */
-URET uffs_ReleaseMountTable(void);								
-
-/** get registered mount table */
-uffs_MountTable * uffs_GetMountTable(void);						
-
-/** register mount table */
-int uffs_RegisterMountTable(uffs_MountTable *mtab);				
-
-/** get matched mount point from absolute path */
-int uffs_GetMatchedMountPointSize(const char *path);			
-
-/** get uffs device from mount point */
-uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount);	
-
-/** get uffs device from mount point */
-uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len);	
-
-/** get mount point name from uffs device */
-const char * uffs_GetDeviceMountPoint(uffs_Device *dev);		
-
-/** down crease uffs device references by uffs_GetDeviceXXX() */
-void uffs_PutDevice(uffs_Device *dev);							
-
-#ifdef __cplusplus
-}
-#endif
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_mtb.h
+ * \brief mount table related stuff
+ * \author Ricky Zheng
+ */
+
+#ifndef UFFS_MTB_H
+#define UFFS_MTB_H
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+typedef struct uffs_MountTableEntrySt {
+	uffs_Device *dev;
+	int start_block;
+	int end_block;
+	const char *mount;
+	struct uffs_MountTableEntrySt *next;
+} uffs_MountTable;
+
+/** initialize registered mount table */
+URET uffs_InitMountTable(void);									
+
+/** release registered mount table */
+URET uffs_ReleaseMountTable(void);								
+
+/** get registered mount table */
+uffs_MountTable * uffs_GetMountTable(void);						
+
+/** register mount table */
+int uffs_RegisterMountTable(uffs_MountTable *mtab);				
+
+/** get matched mount point from absolute path */
+int uffs_GetMatchedMountPointSize(const char *path);			
+
+/** get uffs device from mount point */
+uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount);	
+
+/** get uffs device from mount point */
+uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len);	
+
+/** get mount point name from uffs device */
+const char * uffs_GetDeviceMountPoint(uffs_Device *dev);		
+
+/** down crease uffs device references by uffs_GetDeviceXXX() */
+void uffs_PutDevice(uffs_Device *dev);							
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 65 - 65
components/dfs/filesystems/uffs/src/inc/uffs/uffs_os.h

@@ -1,65 +1,65 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef UFFS_OS_H
-#define UFFS_OS_H
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_core.h"
-
-#define UFFS_TASK_ID_NOT_EXIST	-1
-
-typedef int OSSEM;
-
-/* OS specific functions */
-int uffs_SemCreate(int n);
-int uffs_SemWait(int sem);
-int uffs_SemSignal(int sem);
-int uffs_SemDelete(int sem);
-
-void uffs_CriticalEnter(void);
-void uffs_CriticalExit(void);
-
-int uffs_OSGetTaskId(void);	//get current task id
-unsigned int uffs_GetCurDateTime(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef UFFS_OS_H
+#define UFFS_OS_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_core.h"
+
+#define UFFS_TASK_ID_NOT_EXIST	-1
+
+typedef int OSSEM;
+
+/* OS specific functions */
+int uffs_SemCreate(int n);
+int uffs_SemWait(int sem);
+int uffs_SemSignal(int sem);
+int uffs_SemDelete(int sem);
+
+void uffs_CriticalEnter(void);
+void uffs_CriticalExit(void);
+
+int uffs_OSGetTaskId(void);	//get current task id
+unsigned int uffs_GetCurDateTime(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 92 - 92
components/dfs/filesystems/uffs/src/inc/uffs/uffs_pool.h

@@ -1,92 +1,92 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_pool.h
- * \brief Fast fixed size memory pool management.
- * \author Ricky Zheng, Simon Kallweit
- */
-
-#ifndef _UFFS_POOL_H_
-#define _UFFS_POOL_H_
-
-
-#include "uffs/uffs_types.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-/**
- * \struct uffs_PoolEntrySt
- * \brief Helper type for free buffer entries.
- */
-typedef struct uffs_PoolEntrySt {
-    struct uffs_PoolEntrySt *next;
-} uffs_PoolEntry;
-
-/**
- * \struct uffs_PoolSt
- * \brief Memory pool.
- */
-typedef struct uffs_PoolSt {
-	u8 *mem;					//!< memory pool
-	u32 buf_size;				//!< size of a buffer
-	u32 num_bufs;				//!< number of buffers in the pool
-	uffs_PoolEntry *free_list;	//!< linked list of free buffers
-	int sem;					//!< buffer lock
-} uffs_Pool;
-
-URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs);
-URET uffs_PoolRelease(uffs_Pool *pool);
-
-UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p);
-
-void *uffs_PoolGet(uffs_Pool *pool);
-void *uffs_PoolGetLocked(uffs_Pool *pool);
-
-int uffs_PoolPut(uffs_Pool *pool, void *p);
-int uffs_PoolPutLocked(uffs_Pool *pool, void *p);
-
-void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index);
-u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p);
-UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p);
-
-void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from);
-
-int uffs_PoolGetFreeCount(uffs_Pool *pool);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _UFFS_POOL_H_
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_pool.h
+ * \brief Fast fixed size memory pool management.
+ * \author Ricky Zheng, Simon Kallweit
+ */
+
+#ifndef _UFFS_POOL_H_
+#define _UFFS_POOL_H_
+
+
+#include "uffs/uffs_types.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * \struct uffs_PoolEntrySt
+ * \brief Helper type for free buffer entries.
+ */
+typedef struct uffs_PoolEntrySt {
+    struct uffs_PoolEntrySt *next;
+} uffs_PoolEntry;
+
+/**
+ * \struct uffs_PoolSt
+ * \brief Memory pool.
+ */
+typedef struct uffs_PoolSt {
+	u8 *mem;					//!< memory pool
+	u32 buf_size;				//!< size of a buffer
+	u32 num_bufs;				//!< number of buffers in the pool
+	uffs_PoolEntry *free_list;	//!< linked list of free buffers
+	int sem;					//!< buffer lock
+} uffs_Pool;
+
+URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs);
+URET uffs_PoolRelease(uffs_Pool *pool);
+
+UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p);
+
+void *uffs_PoolGet(uffs_Pool *pool);
+void *uffs_PoolGetLocked(uffs_Pool *pool);
+
+int uffs_PoolPut(uffs_Pool *pool, void *p);
+int uffs_PoolPutLocked(uffs_Pool *pool, void *p);
+
+void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index);
+u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p);
+UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p);
+
+void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from);
+
+int uffs_PoolGetFreeCount(uffs_Pool *pool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _UFFS_POOL_H_

+ 243 - 243
components/dfs/filesystems/uffs/src/inc/uffs/uffs_public.h

@@ -1,243 +1,243 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_public.h
- * \brief public data structures for uffs
- * \author Ricky Zheng
- */
-
-#ifndef _UFFS_PUBLIC_H_
-#define _UFFS_PUBLIC_H_
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-/**
- * \struct uffs_TagStoreSt
- * \brief uffs tag, 8 bytes, will be store in page spare area.
- */
-struct uffs_TagStoreSt {
-	u32 dirty:1;		//!< 0: dirty, 1: clear
-	u32 valid:1;		//!< 0: valid, 1: invalid
-	u32 type:2;			//!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
-	u32 block_ts:2;		//!< time stamp of block;
-	u32 data_len:12;	//!< length of page data
-	u32 serial:14;		//!< serial number
-
-	u32 parent:10;		//!< parent's serial number
-	u32 page_id:6;		//!< page id
-	u32 reserved:4;		//!< reserved, for UFFS2
-	u32 tag_ecc:12;		//!< tag ECC
-};
-
-#define TAG_ECC_DEFAULT (0xFFF)	//!< 12-bit '1'
-
-/**
- * \struct uffs_TagStoreSt_8
- * \brief this data structure describes the page status, for 8 bytes page spare.
- * \note there is no tag ecc for this !
- */
-struct uffs_TagStoreSt_8 {
-	u32 dirty:1;			//!< 0: dirty, 1: clear
-	u32 valid:1;			//!< 0: valid, 1: invalid
-	u32 type:2;				//!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
-	u32 block_ts:2;			//!< time stamp of block;
-	u32 page_id:5;			//!< page id
-	u32 parent:7;			//!< parent's serial number
-	u32 serial:8;			//!< serial number
-	u32 data_len:8;			//!< length of page data
-};
-
-/** 
- * \struct uffs_TagsSt
- */
-struct uffs_TagsSt {
-	struct uffs_TagStoreSt s;		/* store must be the first member */
-
-	/** data_sum for file or dir name */
-	u16 data_sum;
-
-	/**
-	 * block_status is not covered by tag_ecc.
-	 * it's loaded from flash but not directly write to flash.
-	 */
-	u8 block_status;
-
-	/** internal used */
-	u8 _dirty:1;			//!< raw data, before doing ecc correction
-	u8 _valid:1;			//!< raw data, before doing ecc correction
-};
-
-/** 
- * \struct uffs_MiniHeaderSt
- * \brief the mini header resides on the head of page data
- */
-struct uffs_MiniHeaderSt {
-	u8 status;
-	u8 reserved;
-	u16 crc;
-};
-
-
-/** uffs_TagsSt.dirty */
-#define TAG_VALID		0
-#define TAG_INVALID		1
-
-/** uffs_TagsSt.valid */
-#define TAG_DIRTY		0
-#define TAG_CLEAR		1
-
-#define TAG_IS_DIRTY(tag) ((tag)->s.dirty == TAG_DIRTY)
-#define TAG_IS_VALID(tag) ((tag)->s.valid == TAG_VALID)
-#define TAG_SERIAL(tag) (tag)->s.serial
-#define TAG_PARENT(tag) (tag)->s.parent
-#define TAG_PAGE_ID(tag) (tag)->s.page_id
-#define TAG_DATA_LEN(tag) (tag)->s.data_len
-#define TAG_TYPE(tag) (tag)->s.type
-#define TAG_BLOCK_TS(tag) (tag)->s.block_ts
-
-
-int uffs_GetFirstBlockTimeStamp(void);
-int uffs_GetNextBlockTimeStamp(int prev);
-UBOOL uffs_IsSrcNewerThanObj(int src, int obj);
-
-
-#include "uffs_device.h"
-
-
-
-/********************************** debug & error *************************************/
-#define UFFS_ERR_NOISY		-1
-#define UFFS_ERR_NORMAL		0
-#define UFFS_ERR_SERIOUS	1
-#define UFFS_ERR_DEAD		2
-
-#define TENDSTR "\n"
-
-//#define UFFS_DBG_LEVEL	UFFS_ERR_NORMAL	
-#define UFFS_DBG_LEVEL	UFFS_ERR_NOISY	
-
-void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...);
-
-#define uffs_Perror(level, fmt, ... ) \
-	uffs_DebugMessage(level, PFX, TENDSTR, fmt, ## __VA_ARGS__)
-
-#define uffs_PerrorRaw(level, fmt, ... ) \
-	uffs_DebugMessage(level, NULL, NULL, fmt, ## __VA_ARGS__)
-
-
-
-void uffs_AssertCall(const char *file, int line, const char *msg);
-
-#define uffs_Assert(expr, msg)												\
-	do {																	\
-		if (!(expr))														\
-			uffs_AssertCall(__FILE__, __LINE__, msg);						\
-	} while(0)
-
-/********************************** NAND **********************************************/
-//NAND flash specific file must implement these interface
-URET uffs_LoadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
-URET uffs_WritePageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
-URET uffs_MakePageValid(uffs_Device *dev, int block, int page, uffs_Tags *tag);
-UBOOL uffs_IsBlockBad(uffs_Device *dev, uffs_BlockInfo *bc);
-
-/********************************** Public defines *****************************/
-/**
- * \def UFFS_ALL_PAGES 
- * \brief UFFS_ALL_PAGES if this value presented, that means the objects are all pages in the block
- */
-#define UFFS_ALL_PAGES (0xffff)
-
-/** 
- * \def UFFS_INVALID_PAGE
- * \brief macro for invalid page number
- */
-#define UFFS_INVALID_PAGE	(0xfffe)
-#define UFFS_INVALID_BLOCK	(0xfffe)
-
-
-URET uffs_NewBlock(uffs_Device *dev, u16 block, uffs_Tags *tag, uffs_Buf *buf);
-URET uffs_BlockRecover(uffs_Device *dev, uffs_BlockInfo *old, u16 newBlock);
-URET uffs_PageRecover(uffs_Device *dev, 
-					  uffs_BlockInfo *bc, 
-					  u16 oldPage, 
-					  u16 newPage, 
-					  uffs_Buf *buf);
-int uffs_FindFreePageInBlock(uffs_Device *dev, uffs_BlockInfo *bc);
-u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
-u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc);
-u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom);
-u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id);
-
-u8 uffs_MakeSum8(const void *p, int len);
-u16 uffs_MakeSum16(const void *p, int len);
-URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi);
-
-int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type);
-UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
-int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc);
-UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc);
-
-int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc);
-
-
-int uffs_GetDeviceUsed(uffs_Device *dev);
-int uffs_GetDeviceFree(uffs_Device *dev);
-int uffs_GetDeviceTotal(uffs_Device *dev);
-
-URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header);
-
-
-/************************************************************************/
-/*  init functions                                                                     */
-/************************************************************************/
-URET uffs_InitDevice(uffs_Device *dev);
-URET uffs_ReleaseDevice(uffs_Device *dev);
-
-
-URET uffs_InitFlashClass(uffs_Device *dev);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif	// _UFFS_PUBLIC_H_
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_public.h
+ * \brief public data structures for uffs
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_PUBLIC_H_
+#define _UFFS_PUBLIC_H_
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * \struct uffs_TagStoreSt
+ * \brief uffs tag, 8 bytes, will be store in page spare area.
+ */
+struct uffs_TagStoreSt {
+	u32 dirty:1;		//!< 0: dirty, 1: clear
+	u32 valid:1;		//!< 0: valid, 1: invalid
+	u32 type:2;			//!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
+	u32 block_ts:2;		//!< time stamp of block;
+	u32 data_len:12;	//!< length of page data
+	u32 serial:14;		//!< serial number
+
+	u32 parent:10;		//!< parent's serial number
+	u32 page_id:6;		//!< page id
+	u32 reserved:4;		//!< reserved, for UFFS2
+	u32 tag_ecc:12;		//!< tag ECC
+};
+
+#define TAG_ECC_DEFAULT (0xFFF)	//!< 12-bit '1'
+
+/**
+ * \struct uffs_TagStoreSt_8
+ * \brief this data structure describes the page status, for 8 bytes page spare.
+ * \note there is no tag ecc for this !
+ */
+struct uffs_TagStoreSt_8 {
+	u32 dirty:1;			//!< 0: dirty, 1: clear
+	u32 valid:1;			//!< 0: valid, 1: invalid
+	u32 type:2;				//!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
+	u32 block_ts:2;			//!< time stamp of block;
+	u32 page_id:5;			//!< page id
+	u32 parent:7;			//!< parent's serial number
+	u32 serial:8;			//!< serial number
+	u32 data_len:8;			//!< length of page data
+};
+
+/** 
+ * \struct uffs_TagsSt
+ */
+struct uffs_TagsSt {
+	struct uffs_TagStoreSt s;		/* store must be the first member */
+
+	/** data_sum for file or dir name */
+	u16 data_sum;
+
+	/**
+	 * block_status is not covered by tag_ecc.
+	 * it's loaded from flash but not directly write to flash.
+	 */
+	u8 block_status;
+
+	/** internal used */
+	u8 _dirty:1;			//!< raw data, before doing ecc correction
+	u8 _valid:1;			//!< raw data, before doing ecc correction
+};
+
+/** 
+ * \struct uffs_MiniHeaderSt
+ * \brief the mini header resides on the head of page data
+ */
+struct uffs_MiniHeaderSt {
+	u8 status;
+	u8 reserved;
+	u16 crc;
+};
+
+
+/** uffs_TagsSt.dirty */
+#define TAG_VALID		0
+#define TAG_INVALID		1
+
+/** uffs_TagsSt.valid */
+#define TAG_DIRTY		0
+#define TAG_CLEAR		1
+
+#define TAG_IS_DIRTY(tag) ((tag)->s.dirty == TAG_DIRTY)
+#define TAG_IS_VALID(tag) ((tag)->s.valid == TAG_VALID)
+#define TAG_SERIAL(tag) (tag)->s.serial
+#define TAG_PARENT(tag) (tag)->s.parent
+#define TAG_PAGE_ID(tag) (tag)->s.page_id
+#define TAG_DATA_LEN(tag) (tag)->s.data_len
+#define TAG_TYPE(tag) (tag)->s.type
+#define TAG_BLOCK_TS(tag) (tag)->s.block_ts
+
+
+int uffs_GetFirstBlockTimeStamp(void);
+int uffs_GetNextBlockTimeStamp(int prev);
+UBOOL uffs_IsSrcNewerThanObj(int src, int obj);
+
+
+#include "uffs_device.h"
+
+
+
+/********************************** debug & error *************************************/
+#define UFFS_ERR_NOISY		-1
+#define UFFS_ERR_NORMAL		0
+#define UFFS_ERR_SERIOUS	1
+#define UFFS_ERR_DEAD		2
+
+#define TENDSTR "\n"
+
+//#define UFFS_DBG_LEVEL	UFFS_ERR_NORMAL	
+#define UFFS_DBG_LEVEL	UFFS_ERR_DEAD	
+
+void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...);
+
+#define uffs_Perror(level, fmt, ... ) \
+	uffs_DebugMessage(level, PFX, TENDSTR, fmt, ## __VA_ARGS__)
+
+#define uffs_PerrorRaw(level, fmt, ... ) \
+	uffs_DebugMessage(level, NULL, NULL, fmt, ## __VA_ARGS__)
+
+
+
+void uffs_AssertCall(const char *file, int line, const char *msg);
+
+#define uffs_Assert(expr, msg)												\
+	do {																	\
+		if (!(expr))														\
+			uffs_AssertCall(__FILE__, __LINE__, msg);						\
+	} while(0)
+
+/********************************** NAND **********************************************/
+//NAND flash specific file must implement these interface
+URET uffs_LoadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
+URET uffs_WritePageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
+URET uffs_MakePageValid(uffs_Device *dev, int block, int page, uffs_Tags *tag);
+UBOOL uffs_IsBlockBad(uffs_Device *dev, uffs_BlockInfo *bc);
+
+/********************************** Public defines *****************************/
+/**
+ * \def UFFS_ALL_PAGES 
+ * \brief UFFS_ALL_PAGES if this value presented, that means the objects are all pages in the block
+ */
+#define UFFS_ALL_PAGES (0xffff)
+
+/** 
+ * \def UFFS_INVALID_PAGE
+ * \brief macro for invalid page number
+ */
+#define UFFS_INVALID_PAGE	(0xfffe)
+#define UFFS_INVALID_BLOCK	(0xfffe)
+
+
+URET uffs_NewBlock(uffs_Device *dev, u16 block, uffs_Tags *tag, uffs_Buf *buf);
+URET uffs_BlockRecover(uffs_Device *dev, uffs_BlockInfo *old, u16 newBlock);
+URET uffs_PageRecover(uffs_Device *dev, 
+					  uffs_BlockInfo *bc, 
+					  u16 oldPage, 
+					  u16 newPage, 
+					  uffs_Buf *buf);
+int uffs_FindFreePageInBlock(uffs_Device *dev, uffs_BlockInfo *bc);
+u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
+u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc);
+u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom);
+u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id);
+
+u8 uffs_MakeSum8(const void *p, int len);
+u16 uffs_MakeSum16(const void *p, int len);
+URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi);
+
+int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type);
+UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
+int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc);
+UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc);
+
+int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc);
+
+
+int uffs_GetDeviceUsed(uffs_Device *dev);
+int uffs_GetDeviceFree(uffs_Device *dev);
+int uffs_GetDeviceTotal(uffs_Device *dev);
+
+URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header);
+
+
+/************************************************************************/
+/*  init functions                                                                     */
+/************************************************************************/
+URET uffs_InitDevice(uffs_Device *dev);
+URET uffs_ReleaseDevice(uffs_Device *dev);
+
+
+URET uffs_InitFlashClass(uffs_Device *dev);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif	// _UFFS_PUBLIC_H_
+

+ 221 - 221
components/dfs/filesystems/uffs/src/inc/uffs/uffs_tree.h

@@ -1,221 +1,221 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef _UFFS_TREE_H_
-#define _UFFS_TREE_H_
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_pool.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#define UFFS_TYPE_DIR		0
-#define UFFS_TYPE_FILE		1
-#define UFFS_TYPE_DATA		2
-#define UFFS_TYPE_RESV		3
-#define UFFS_TYPE_INVALID	0xFF
-
-struct BlockListSt {	/* 10 bytes */
-	struct uffs_TreeNodeSt * next;
-	struct uffs_TreeNodeSt * prev;
-	u16 block;
-};
-
-struct DirhSt {		/* 8 bytes */
-	u16 checksum;	/* check sum of dir name */
-	u16 block;
-	u16 parent;
-	u16 serial;
-};
-
-
-struct FilehSt {	/* 12 bytes */
-	u16 block;
-	u16 checksum;	/* check sum of file name */
-	u16 parent;
-	u16 serial;
-	u32 len;		/* file length total */
-};
-
-struct FdataSt {	/* 10 bytes */
-	u16 block;
-	u16 parent;
-	u32 len;		/* file data length on this block */
-	u16 serial;
-};
-
-//UFFS TreeNode (14 or 16 bytes)
-typedef struct uffs_TreeNodeSt {
-	union {
-		struct BlockListSt list;
-		struct DirhSt dir;
-		struct FilehSt file;
-		struct FdataSt data;
-	} u;
-	u16 hash_next;		
-#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
-	u16 hash_prev;			
-#endif
-} TreeNode;
-
-
-//TODO: UFFS2 Tree structures
-/*
-struct FdataSt {
-	u32 len;
-};
-
-struct filebSt {
-	u16 bls;		//how many blocks this file contents ...
-	u8 offs;		//the offset of this file header on FILE block
-	u8 sum;			//short sum of file name
-};
-
-//Extra data structure for storing file length information
-struct FilehSt {
-	u32 len;
-};
-
-//UFFS2 TreeNode (12 bytes)
-typedef struct uffs_TreeNodeSt {
-	u16 nextIdx;
-	u16 block;
-	u16 parent;
-	u16 serial;
-	union {
-		struct FilehSt h;
-		struct filedSt file;
-		struct data;
-	} u;
-} TreeNode;
-
-*/
-
-
-#define EMPTY_NODE 0xffff				//!< special index num of empty node.
-
-#define ROOT_DIR_SERIAL	0				//!< serial num of root dir
-#define MAX_UFFS_FSN			0x3ff	//!< maximum dir|file serial number (uffs_TagStore#parent: 10 bits)
-#define MAX_UFFS_FDN			0x3fff	//!< maximum file data block serial numbers (uffs_TagStore#serial: 14 bits)
-#define PARENT_OF_ROOT			0xfffd	//!< parent of ROOT ? kidding me ...
-#define INVALID_UFFS_SERIAL		0xffff	//!< invalid serial num
-
-#define DIR_NODE_HASH_MASK		0x1f
-#define DIR_NODE_ENTRY_LEN		(DIR_NODE_HASH_MASK + 1)
-
-#define FILE_NODE_HASH_MASK		0x3f
-#define FILE_NODE_ENTRY_LEN		(FILE_NODE_HASH_MASK + 1)
-
-#define DATA_NODE_HASH_MASK		0x1ff
-#define DATA_NODE_ENTRY_LEN		(DATA_NODE_HASH_MASK + 1)
-#define FROM_IDX(idx, pool)		((TreeNode *)uffs_PoolGetBufByIndex(pool, idx))
-#define TO_IDX(p, pool)			((u16)uffs_PoolGetIndex(pool, (void *) p))
-
-
-#define GET_FILE_HASH(serial)			(serial & FILE_NODE_HASH_MASK)
-#define GET_DIR_HASH(serial)			(serial & DIR_NODE_HASH_MASK)
-#define GET_DATA_HASH(parent, serial)	((parent + serial) & DATA_NODE_HASH_MASK)
-
-
-struct uffs_TreeSt {
-	TreeNode *erased;					//!< erased block list head
-	TreeNode *erased_tail;				//!< erased block list tail
-	int erased_count;					//!< erased block counter
-	TreeNode *bad;						//!< bad block list
-	int bad_count;						//!< bad block count
-	u16 dir_entry[DIR_NODE_ENTRY_LEN];
-	u16 file_entry[FILE_NODE_ENTRY_LEN];
-	u16 data_entry[DATA_NODE_ENTRY_LEN];
-	u16 max_serial;
-};
-
-
-URET uffs_TreeInit(uffs_Device *dev);
-URET uffs_TreeRelease(uffs_Device *dev);
-URET uffs_BuildTree(uffs_Device *dev);
-u16 uffs_FindFreeFsnSerial(uffs_Device *dev);
-TreeNode * uffs_TreeFindFileNode(uffs_Device *dev, u16 serial);
-TreeNode * uffs_TreeFindFileNodeWithParent(uffs_Device *dev, u16 parent);
-TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial);
-TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent);
-TreeNode * uffs_TreeFindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
-TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
-TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial);
-
-
-TreeNode * uffs_TreeFindDirNodeByBlock(uffs_Device *dev, u16 block);
-TreeNode * uffs_TreeFindFileNodeByBlock(uffs_Device *dev, u16 block);
-TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block);
-TreeNode * uffs_TreeFindErasedNodeByBlock(uffs_Device *dev, u16 block);
-TreeNode * uffs_TreeFindBadNodeByBlock(uffs_Device *dev, u16 block);
-
-#define SEARCH_REGION_DIR		1
-#define SEARCH_REGION_FILE		2
-#define SEARCH_REGION_DATA		4
-#define SEARCH_REGION_BAD		8
-#define SEARCH_REGION_ERASED	16
-TreeNode * uffs_TreeFindNodeByBlock(uffs_Device *dev, u16 block, int *region);
-
-
-
-UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type);
-
-TreeNode * uffs_TreeGetErasedNode(uffs_Device *dev);
-
-void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node);
-void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node);
-void uffs_TreeInsertToErasedListTail(uffs_Device *dev, TreeNode *node);
-void uffs_TreeInsertToBadBlockList(uffs_Device *dev, TreeNode *node);
-
-void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node);
-
-void uffs_TreeSetNodeBlock(u8 type, TreeNode *node, u16 block);
-
-
-
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
-#endif
-
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef _UFFS_TREE_H_
+#define _UFFS_TREE_H_
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_pool.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#define UFFS_TYPE_DIR		0
+#define UFFS_TYPE_FILE		1
+#define UFFS_TYPE_DATA		2
+#define UFFS_TYPE_RESV		3
+#define UFFS_TYPE_INVALID	0xFF
+
+struct BlockListSt {	/* 10 bytes */
+	struct uffs_TreeNodeSt * next;
+	struct uffs_TreeNodeSt * prev;
+	u16 block;
+};
+
+struct DirhSt {		/* 8 bytes */
+	u16 checksum;	/* check sum of dir name */
+	u16 block;
+	u16 parent;
+	u16 serial;
+};
+
+
+struct FilehSt {	/* 12 bytes */
+	u16 block;
+	u16 checksum;	/* check sum of file name */
+	u16 parent;
+	u16 serial;
+	u32 len;		/* file length total */
+};
+
+struct FdataSt {	/* 10 bytes */
+	u16 block;
+	u16 parent;
+	u32 len;		/* file data length on this block */
+	u16 serial;
+};
+
+//UFFS TreeNode (14 or 16 bytes)
+typedef struct uffs_TreeNodeSt {
+	union {
+		struct BlockListSt list;
+		struct DirhSt dir;
+		struct FilehSt file;
+		struct FdataSt data;
+	} u;
+	u16 hash_next;		
+#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
+	u16 hash_prev;			
+#endif
+} TreeNode;
+
+
+//TODO: UFFS2 Tree structures
+/*
+struct FdataSt {
+	u32 len;
+};
+
+struct filebSt {
+	u16 bls;		//how many blocks this file contents ...
+	u8 offs;		//the offset of this file header on FILE block
+	u8 sum;			//short sum of file name
+};
+
+//Extra data structure for storing file length information
+struct FilehSt {
+	u32 len;
+};
+
+//UFFS2 TreeNode (12 bytes)
+typedef struct uffs_TreeNodeSt {
+	u16 nextIdx;
+	u16 block;
+	u16 parent;
+	u16 serial;
+	union {
+		struct FilehSt h;
+		struct filedSt file;
+		struct data;
+	} u;
+} TreeNode;
+
+*/
+
+
+#define EMPTY_NODE 0xffff				//!< special index num of empty node.
+
+#define ROOT_DIR_SERIAL	0				//!< serial num of root dir
+#define MAX_UFFS_FSN			0x3ff	//!< maximum dir|file serial number (uffs_TagStore#parent: 10 bits)
+#define MAX_UFFS_FDN			0x3fff	//!< maximum file data block serial numbers (uffs_TagStore#serial: 14 bits)
+#define PARENT_OF_ROOT			0xfffd	//!< parent of ROOT ? kidding me ...
+#define INVALID_UFFS_SERIAL		0xffff	//!< invalid serial num
+
+#define DIR_NODE_HASH_MASK		0x1f
+#define DIR_NODE_ENTRY_LEN		(DIR_NODE_HASH_MASK + 1)
+
+#define FILE_NODE_HASH_MASK		0x3f
+#define FILE_NODE_ENTRY_LEN		(FILE_NODE_HASH_MASK + 1)
+
+#define DATA_NODE_HASH_MASK		0x1ff
+#define DATA_NODE_ENTRY_LEN		(DATA_NODE_HASH_MASK + 1)
+#define FROM_IDX(idx, pool)		((TreeNode *)uffs_PoolGetBufByIndex(pool, idx))
+#define TO_IDX(p, pool)			((u16)uffs_PoolGetIndex(pool, (void *) p))
+
+
+#define GET_FILE_HASH(serial)			(serial & FILE_NODE_HASH_MASK)
+#define GET_DIR_HASH(serial)			(serial & DIR_NODE_HASH_MASK)
+#define GET_DATA_HASH(parent, serial)	((parent + serial) & DATA_NODE_HASH_MASK)
+
+
+struct uffs_TreeSt {
+	TreeNode *erased;					//!< erased block list head
+	TreeNode *erased_tail;				//!< erased block list tail
+	int erased_count;					//!< erased block counter
+	TreeNode *bad;						//!< bad block list
+	int bad_count;						//!< bad block count
+	u16 dir_entry[DIR_NODE_ENTRY_LEN];
+	u16 file_entry[FILE_NODE_ENTRY_LEN];
+	u16 data_entry[DATA_NODE_ENTRY_LEN];
+	u16 max_serial;
+};
+
+
+URET uffs_TreeInit(uffs_Device *dev);
+URET uffs_TreeRelease(uffs_Device *dev);
+URET uffs_BuildTree(uffs_Device *dev);
+u16 uffs_FindFreeFsnSerial(uffs_Device *dev);
+TreeNode * uffs_TreeFindFileNode(uffs_Device *dev, u16 serial);
+TreeNode * uffs_TreeFindFileNodeWithParent(uffs_Device *dev, u16 parent);
+TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial);
+TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent);
+TreeNode * uffs_TreeFindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
+TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
+TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial);
+
+
+TreeNode * uffs_TreeFindDirNodeByBlock(uffs_Device *dev, u16 block);
+TreeNode * uffs_TreeFindFileNodeByBlock(uffs_Device *dev, u16 block);
+TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block);
+TreeNode * uffs_TreeFindErasedNodeByBlock(uffs_Device *dev, u16 block);
+TreeNode * uffs_TreeFindBadNodeByBlock(uffs_Device *dev, u16 block);
+
+#define SEARCH_REGION_DIR		1
+#define SEARCH_REGION_FILE		2
+#define SEARCH_REGION_DATA		4
+#define SEARCH_REGION_BAD		8
+#define SEARCH_REGION_ERASED	16
+TreeNode * uffs_TreeFindNodeByBlock(uffs_Device *dev, u16 block, int *region);
+
+
+
+UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type);
+
+TreeNode * uffs_TreeGetErasedNode(uffs_Device *dev);
+
+void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node);
+void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node);
+void uffs_TreeInsertToErasedListTail(uffs_Device *dev, TreeNode *node);
+void uffs_TreeInsertToBadBlockList(uffs_Device *dev, TreeNode *node);
+
+void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node);
+
+void uffs_TreeSetNodeBlock(u8 type, TreeNode *node, u16 block);
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
+
+

+ 158 - 156
components/dfs/filesystems/uffs/src/inc/uffs/uffs_types.h

@@ -1,156 +1,158 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef UFFS_TYPES_H
-#define UFFS_TYPES_H
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-#ifdef _UBASE_
-#include <sys/utypes.h>
-#endif
-
-/** 
- * \file uffs_types.h
- * \brief basic types used on uffs
- * \author Ricky Zheng
- */
-
-/* basic types */
-
-/** \typedef i8 
- * \brief 8 bit integer
- */
-typedef char i8;
-
-/** \typedef u8 
- * \brief 8 bit unsigned integer
- */
-typedef unsigned char u8;
-
-/** \typedef i16 
- * \brief 16 bit integer
- */
-typedef short int i16;
-
-
-/** \typedef u16
- * \brief 16 bit unsigned integer
- */
-typedef unsigned short int u16;
-
-
-/** \typedef i32
- * \brief 32 bit integer
- */
-typedef int i32;
-
-/** \typedef u32 
- * \brief 32 bit unsigned integer
- */
-typedef unsigned int u32;
-
-
-#ifndef _UBASE_
-
-#ifndef TRUE
-#define TRUE	1
-#endif
-
-#ifndef FALSE
-#define FALSE	0
-#endif
-
-/* boolean type */
-
-/** \typedef UBOOL 
- * \brief boolean type for uffs, the value would be: #U_TRUE or #U_FALSE
- */
-typedef int UBOOL;
-
-/** \def U_TRUE 
- * \brief boolean true for uffs
- */
-#define U_TRUE (TRUE)
-
-
-/** \def U_FALSE 
- * \brief boolean false for uffs
- */
-#define U_FALSE (FALSE)
-
-
-/** \typedef URET 
- * \brief return type for uffs, should be #U_FAIL or #U_SUCC
- */
-typedef int URET;
-
-/** \def U_FAIL 
- * \brief indicator of fail
- */
-#define U_FAIL -1
-
-/** \def U_SUCC 
- * \brief indicator of successful
- */
-#define U_SUCC 0
-
-/** \def IS_SUCC(ret) 
- * \brief is it successful ?
- */
-#define IS_SUCC(ret) (ret >= 0 ? U_TRUE : U_FALSE)
-
-
-/** \def IS_FAIL(ret) 
- * \brief is it fail ?
- */
-#define IS_FAIL(ret) (ret < 0 ? U_TRUE : U_FALSE)
-
-#ifndef NULL
-/** \def NULL 
- * \brief zero for pointer
- */
-#define NULL 0
-#endif
-
-#endif // _UBASE_
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef UFFS_TYPES_H
+#define UFFS_TYPES_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifdef _UBASE_
+#include <sys/utypes.h>
+#endif
+
+/** 
+ * \file uffs_types.h
+ * \brief basic types used on uffs
+ * \author Ricky Zheng
+ */
+
+/* basic types */
+
+/** \typedef i8 
+ * \brief 8 bit integer
+ */
+typedef char i8;
+
+/** \typedef u8 
+ * \brief 8 bit unsigned integer
+ */
+typedef unsigned char u8;
+
+/** \typedef i16 
+ * \brief 16 bit integer
+ */
+typedef short int i16;
+
+
+/** \typedef u16
+ * \brief 16 bit unsigned integer
+ */
+typedef unsigned short int u16;
+
+
+/** \typedef i32
+ * \brief 32 bit integer
+ */
+typedef int i32;
+
+/** \typedef u32 
+ * \brief 32 bit unsigned integer
+ */
+typedef unsigned int u32;
+
+
+#ifndef _UBASE_
+
+#ifndef TRUE
+#define TRUE	1
+#endif
+
+#ifndef FALSE
+#define FALSE	0
+#endif
+
+/* boolean type */
+
+/** \typedef UBOOL 
+ * \brief boolean type for uffs, the value would be: #U_TRUE or #U_FALSE
+ */
+typedef int UBOOL;
+
+/** \def U_TRUE 
+ * \brief boolean true for uffs
+ */
+#define U_TRUE (TRUE)
+
+
+/** \def U_FALSE 
+ * \brief boolean false for uffs
+ */
+#define U_FALSE (FALSE)
+
+
+/** \typedef URET 
+ * \brief return type for uffs, should be #U_FAIL or #U_SUCC
+ */
+typedef int URET;
+
+/** \def U_FAIL 
+ * \brief indicator of fail
+ */
+#define U_FAIL -1
+
+/** \def U_SUCC 
+ * \brief indicator of successful
+ */
+#define U_SUCC 0
+
+/** \def IS_SUCC(ret) 
+ * \brief is it successful ?
+ */
+#define IS_SUCC(ret) (ret >= 0 ? U_TRUE : U_FALSE)
+
+
+/** \def IS_FAIL(ret) 
+ * \brief is it fail ?
+ */
+#define IS_FAIL(ret) (ret < 0 ? U_TRUE : U_FALSE)
+
+#ifndef NULL
+/** \def NULL 
+ * \brief zero for pointer
+ */
+#define NULL 0
+#endif
+
+#endif // _UBASE_
+

+/* RT-Thread info */

+#define memset rt_memset
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 85 - 85
components/dfs/filesystems/uffs/src/inc/uffs/uffs_utils.h

@@ -1,85 +1,85 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef UFFS_UTILS_H
-#define UFFS_UTILS_H
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_core.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-//begin method
-#define PARTITION_FOLLOW_PRIVATE	0
-#define PARTITION_BEGIN_ABSOLUTE	1
-	
-//alloc method
-#define ALLOC_BY_SIZE		0
-#define ALLOC_BY_ABSOLUTE	1
-#define ALLOC_USE_FREE		2
-
-//struct uffs_PartitionMakeInfoSt {
-//	u32 begin_method;
-//	u32	alloc_method;
-//	union{
-//		u32 begin_block;
-//		u32 begin_offset;
-//	};
-//	union{
-//		u32 end_block;
-//		u32 size;
-//		u32 remain_size;
-//	};
-//	u32 access;
-//};
-//
-//
-//URET uffs_MakePartition(struct uffs_DeviceSt *dev, struct uffs_PartitionMakeInfoSt *pi, int nums);
-//
-//void uffs_ListPartition(struct uffs_DeviceSt *dev);
-
-//get UFFS disk version, if fail, return 0
-int uffs_GetUFFSVersion(struct uffs_DeviceSt *dev);
-
-URET uffs_FormatDevice(uffs_Device *dev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef UFFS_UTILS_H
+#define UFFS_UTILS_H
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_core.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+//begin method
+#define PARTITION_FOLLOW_PRIVATE	0
+#define PARTITION_BEGIN_ABSOLUTE	1
+	
+//alloc method
+#define ALLOC_BY_SIZE		0
+#define ALLOC_BY_ABSOLUTE	1
+#define ALLOC_USE_FREE		2
+
+//struct uffs_PartitionMakeInfoSt {
+//	u32 begin_method;
+//	u32	alloc_method;
+//	union{
+//		u32 begin_block;
+//		u32 begin_offset;
+//	};
+//	union{
+//		u32 end_block;
+//		u32 size;
+//		u32 remain_size;
+//	};
+//	u32 access;
+//};
+//
+//
+//URET uffs_MakePartition(struct uffs_DeviceSt *dev, struct uffs_PartitionMakeInfoSt *pi, int nums);
+//
+//void uffs_ListPartition(struct uffs_DeviceSt *dev);
+
+//get UFFS disk version, if fail, return 0
+int uffs_GetUFFSVersion(struct uffs_DeviceSt *dev);
+
+URET uffs_FormatDevice(uffs_Device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 54 - 54
components/dfs/filesystems/uffs/src/inc/uffs/uffs_version.h

@@ -1,54 +1,54 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-#ifndef UFFS_VERSION_H
-#define UFFS_VERSION_H
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#define UFFS_VERSION		0x01030000	//"01.03.0000"
-
-const char * uffs_Version2Str(int ver);
-int uffs_GetVersion(void);
-int uffs_GetMainVersion(int ver);
-int uffs_GetMinorVersion(int ver);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#ifndef UFFS_VERSION_H
+#define UFFS_VERSION_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#define UFFS_VERSION		0x01030000	//"01.03.0000"
+
+const char * uffs_Version2Str(int ver);
+int uffs_GetVersion(void);
+int uffs_GetMainVersion(int ver);
+int uffs_GetMinorVersion(int ver);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 49 - 49
components/dfs/filesystems/uffs/src/uffs/CMakeLists.txt

@@ -1,49 +1,49 @@
-SET (libuffs_SRCS 
-		uffs_badblock.c 
-		uffs_blockinfo.c 
-		uffs_buf.c 
-		uffs_debug.c 
-		uffs_device.c 
-		uffs_ecc.c 
-		uffs_fd.c 
-		uffs_fs.c 
-		uffs_init.c 
-		uffs_mem.c 
-		uffs_pool.c 
-		uffs_public.c 
-		uffs_tree.c 
-		uffs_utils.c
-		uffs_mtb.c
-		uffs_find.c
-		uffs_flash.c
-		uffs_version.c
-	 )
-
-SET (HDR ${uffs_SOURCE_DIR}/src/inc/uffs)
-
-SET (libuffs_HEADS 
-		${HDR}/uffs.h
-		${HDR}/uffs_badblock.h
-		${HDR}/uffs_blockinfo.h
-		${HDR}/uffs_buf.h 
-		${HDR}/uffs_config.h 
-		${HDR}/uffs_core.h 
-		${HDR}/uffs_device.h
-		${HDR}/uffs_ecc.h
-		${HDR}/uffs_fd.h
-		${HDR}/uffs_fs.h
-		${HDR}/uffs_mem.h
-        ${HDR}/uffs_os.h
-        ${HDR}/uffs_pool.h
-        ${HDR}/uffs_public.h
-		${HDR}/uffs_tree.h
-		${HDR}/uffs_types.h
-		${HDR}/uffs_utils.h
-		${HDR}/uffs_mtb.h
-		${HDR}/uffs_find.h
-		${HDR}/uffs_flash.h
-		${HDR}/uffs_version.h
-   )
-
-INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
-ADD_LIBRARY( uffs STATIC ${libuffs_SRCS} ${libuffs_HEADS} )
+SET (libuffs_SRCS 
+		uffs_badblock.c 
+		uffs_blockinfo.c 
+		uffs_buf.c 
+		uffs_debug.c 
+		uffs_device.c 
+		uffs_ecc.c 
+		uffs_fd.c 
+		uffs_fs.c 
+		uffs_init.c 
+		uffs_mem.c 
+		uffs_pool.c 
+		uffs_public.c 
+		uffs_tree.c 
+		uffs_utils.c
+		uffs_mtb.c
+		uffs_find.c
+		uffs_flash.c
+		uffs_version.c
+	 )
+
+SET (HDR ${uffs_SOURCE_DIR}/src/inc/uffs)
+
+SET (libuffs_HEADS 
+		${HDR}/uffs.h
+		${HDR}/uffs_badblock.h
+		${HDR}/uffs_blockinfo.h
+		${HDR}/uffs_buf.h 
+		${HDR}/uffs_config.h 
+		${HDR}/uffs_core.h 
+		${HDR}/uffs_device.h
+		${HDR}/uffs_ecc.h
+		${HDR}/uffs_fd.h
+		${HDR}/uffs_fs.h
+		${HDR}/uffs_mem.h
+        ${HDR}/uffs_os.h
+        ${HDR}/uffs_pool.h
+        ${HDR}/uffs_public.h
+		${HDR}/uffs_tree.h
+		${HDR}/uffs_types.h
+		${HDR}/uffs_utils.h
+		${HDR}/uffs_mtb.h
+		${HDR}/uffs_find.h
+		${HDR}/uffs_flash.h
+		${HDR}/uffs_version.h
+   )
+
+INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
+ADD_LIBRARY( uffs STATIC ${libuffs_SRCS} ${libuffs_HEADS} )

+ 188 - 188
components/dfs/filesystems/uffs/src/uffs/uffs_badblock.c

@@ -1,33 +1,33 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
 */
 
 /**
@@ -39,178 +39,178 @@
 #include "uffs/uffs_fs.h"
 #include "uffs/uffs_config.h"
 #include "uffs/uffs_ecc.h"
-#include "uffs/uffs_badblock.h"
-#include <string.h>
+#include "uffs/uffs_badblock.h"
+
+#include <rtthread.h>
 
 #define PFX "bbl:  "
 
 void uffs_BadBlockInit(uffs_Device *dev)
-{
+{	
 	dev->bad.block = UFFS_INVALID_BLOCK;
 }
 
-
 /** 
  * \brief process bad block: erase bad block, mark it as 'bad' and put the node to bad block list.
  * \param[in] dev uffs device
  * \param[in] node bad block tree node (before the block turn 'bad', it must belong to something ...)
  */
-void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node)
-{
-	if (HAVE_BADBLOCK(dev)) {
-		// mark the bad block
-		uffs_FlashMarkBadBlock(dev, dev->bad.block);
-
-		// and put it into bad block list
-		if (node != NULL)
-			uffs_TreeInsertToBadBlockList(dev, node);
-
-		//clear bad block mark.
-		dev->bad.block = UFFS_INVALID_BLOCK;
-
-	}
+void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node)
+{
+	if (HAVE_BADBLOCK(dev)) {
+		// mark the bad block
+		uffs_FlashMarkBadBlock(dev, dev->bad.block);
+
+		// and put it into bad block list
+		if (node != NULL)
+			uffs_TreeInsertToBadBlockList(dev, node);
+
+		//clear bad block mark.
+		dev->bad.block = UFFS_INVALID_BLOCK;
+
+	}
 }
 
-/** 
- * \brief recover bad block
- * \param[in] dev uffs device
- */
-void uffs_BadBlockRecover(uffs_Device *dev)
-{
-	TreeNode *good, *bad;
-	uffs_Buf *buf;
-	u16 i;
-	u16 page;
-	uffs_BlockInfo *bc = NULL;
-	uffs_Tags *tag;
-	uffs_Tags newTag;
-	UBOOL succRecov;
-	UBOOL goodBlockIsDirty = U_FALSE;
-	int ret;
-	int region;
-	u8 type;
-	
-	if (dev->bad.block == UFFS_INVALID_BLOCK)
-		return;
-
-	// pick up an erased good block
-	good = uffs_TreeGetErasedNode(dev);
-	if (good == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "no free block to replace bad block!");
-		return;
-	}
-
-	//recover block
-	bc = uffs_BlockInfoGet(dev, dev->bad.block);
-	
-	if (bc == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "can't get bad block info");
-		return;
-	}
-
-	succRecov = U_TRUE;
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		page = uffs_FindPageInBlockWithPageId(dev, bc, i);
-		if(page == UFFS_INVALID_PAGE) {
-			break;  //end of last valid page, normal break
-		}
-		page = uffs_FindBestPageInBlock(dev, bc, page);
-		tag = GET_TAG(bc, page);
-		buf = uffs_BufClone(dev, NULL);
-		if (buf == NULL) {	
-			uffs_Perror(UFFS_ERR_SERIOUS, "Can't clone a new buf!");
-			succRecov = U_FALSE;
-			break;
-		}
-		//NOTE: since this is a bad block, we can't guarantee the data is ECC ok, so just load data even ECC is not OK.
-		ret = uffs_LoadPhyDataToBufEccUnCare(dev, buf, bc->block, page);
-		if (ret == U_FAIL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "I/O error ?");
-			uffs_BufFreeClone(dev, buf);
-			succRecov = U_FALSE;
-			break;
-		}
-		buf->data_len = TAG_DATA_LEN(tag);
-		if (buf->data_len > dev->com.pg_data_size) {
-			uffs_Perror(UFFS_ERR_NOISY, "data length over flow!!!");
-			buf->data_len = dev->com.pg_data_size;
-		}
-
-		buf->parent = TAG_PARENT(tag);
-		buf->serial = TAG_SERIAL(tag);
-		buf->type = TAG_TYPE(tag);
-		buf->page_id = TAG_PAGE_ID(tag);
-		
-		newTag = *tag;
-		TAG_BLOCK_TS(&newTag) = uffs_GetNextBlockTimeStamp(TAG_BLOCK_TS(tag));
-
-		ret = uffs_FlashWritePageCombine(dev, good->u.list.block, i, buf, &newTag);
-
-		goodBlockIsDirty = U_TRUE;
-		uffs_BufFreeClone(dev, buf);
-
-		if (ret == UFFS_FLASH_IO_ERR) {
-			uffs_Perror(UFFS_ERR_NORMAL, "I/O error ?");
-			succRecov = U_FALSE;
-			break;
-		}
-	}
-
-
-	if (succRecov == U_TRUE) {
-		//successful recover bad block, so need to mark bad block, and replace with good one
-
-		region = SEARCH_REGION_DIR|SEARCH_REGION_FILE|SEARCH_REGION_DATA;
-		bad = uffs_TreeFindNodeByBlock(dev, dev->bad.block, &region);
-		if (bad != NULL) {
-			switch (region) {
-			case SEARCH_REGION_DIR:
-				bad->u.dir.block = good->u.list.block;
-				type = UFFS_TYPE_DIR;
-				break;
-			case SEARCH_REGION_FILE:
-				bad->u.file.block = good->u.list.block;
-				type = UFFS_TYPE_FILE;
-				break;
-			case SEARCH_REGION_DATA:
-				bad->u.data.block = good->u.list.block;
-				type = UFFS_TYPE_DATA;
-			}
-			
-			//from now, the 'bad' is actually good block :)))
-			uffs_Perror(UFFS_ERR_NOISY, "new bad block %d found, and replaced by %d!", dev->bad.block, good->u.list.block);
-			uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-			//we reuse the 'good' node as bad block node, and process the bad block.
-			good->u.list.block = dev->bad.block;
-			uffs_BadBlockProcess(dev, good);
-		}
-		else {
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't find the reported bad block(%d) in the tree???", dev->bad.block);
-			if (goodBlockIsDirty == U_TRUE)
-				dev->ops->EraseBlock(dev, good->u.list.block);
-			uffs_TreeInsertToErasedListTail(dev, good);
-		}
-	}
-	else {
-		if (goodBlockIsDirty == U_TRUE)
-			dev->ops->EraseBlock(dev, good->u.list.block);
-		uffs_TreeInsertToErasedListTail(dev, good); //put back to erased list
-	}
-
-	uffs_BlockInfoPut(dev, bc);
-
+/** 
+ * \brief recover bad block
+ * \param[in] dev uffs device
+ */
+void uffs_BadBlockRecover(uffs_Device *dev)
+{
+	TreeNode *good, *bad;
+	uffs_Buf *buf;
+	u16 i;
+	u16 page;
+	uffs_BlockInfo *bc = NULL;
+	uffs_Tags *tag;
+	uffs_Tags newTag;
+	UBOOL succRecov;
+	UBOOL goodBlockIsDirty = U_FALSE;
+	int ret;
+	int region;
+	u8 type;
+	
+	if (dev->bad.block == UFFS_INVALID_BLOCK)
+		return;
+
+	// pick up an erased good block
+	good = uffs_TreeGetErasedNode(dev);
+	if (good == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "no free block to replace bad block!");
+		return;
+	}
+
+	//recover block
+	bc = uffs_BlockInfoGet(dev, dev->bad.block);
+	
+	if (bc == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "can't get bad block info");
+		return;
+	}
+
+	succRecov = U_TRUE;
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		page = uffs_FindPageInBlockWithPageId(dev, bc, i);
+		if(page == UFFS_INVALID_PAGE) {
+			break;  //end of last valid page, normal break
+		}
+		page = uffs_FindBestPageInBlock(dev, bc, page);
+		tag = GET_TAG(bc, page);
+		buf = uffs_BufClone(dev, NULL);
+		if (buf == NULL) {	
+			uffs_Perror(UFFS_ERR_SERIOUS, "Can't clone a new buf!");
+			succRecov = U_FALSE;
+			break;
+		}
+		//NOTE: since this is a bad block, we can't guarantee the data is ECC ok, so just load data even ECC is not OK.
+		ret = uffs_LoadPhyDataToBufEccUnCare(dev, buf, bc->block, page);
+		if (ret == U_FAIL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "I/O error ?");
+			uffs_BufFreeClone(dev, buf);
+			succRecov = U_FALSE;
+			break;
+		}
+		buf->data_len = TAG_DATA_LEN(tag);
+		if (buf->data_len > dev->com.pg_data_size) {
+			uffs_Perror(UFFS_ERR_NOISY, "data length over flow!!!");
+			buf->data_len = dev->com.pg_data_size;
+		}
+
+		buf->parent = TAG_PARENT(tag);
+		buf->serial = TAG_SERIAL(tag);
+		buf->type = TAG_TYPE(tag);
+		buf->page_id = TAG_PAGE_ID(tag);
+		
+		newTag = *tag;
+		TAG_BLOCK_TS(&newTag) = uffs_GetNextBlockTimeStamp(TAG_BLOCK_TS(tag));
+
+		ret = uffs_FlashWritePageCombine(dev, good->u.list.block, i, buf, &newTag);
+
+		goodBlockIsDirty = U_TRUE;
+		uffs_BufFreeClone(dev, buf);
+
+		if (ret == UFFS_FLASH_IO_ERR) {
+			uffs_Perror(UFFS_ERR_NORMAL, "I/O error ?");
+			succRecov = U_FALSE;
+			break;
+		}
+	}
+
+
+	if (succRecov == U_TRUE) {
+		//successful recover bad block, so need to mark bad block, and replace with good one
+
+		region = SEARCH_REGION_DIR|SEARCH_REGION_FILE|SEARCH_REGION_DATA;
+		bad = uffs_TreeFindNodeByBlock(dev, dev->bad.block, &region);
+		if (bad != NULL) {
+			switch (region) {
+			case SEARCH_REGION_DIR:
+				bad->u.dir.block = good->u.list.block;
+				type = UFFS_TYPE_DIR;
+				break;
+			case SEARCH_REGION_FILE:
+				bad->u.file.block = good->u.list.block;
+				type = UFFS_TYPE_FILE;
+				break;
+			case SEARCH_REGION_DATA:
+				bad->u.data.block = good->u.list.block;
+				type = UFFS_TYPE_DATA;
+			}
+			
+			//from now, the 'bad' is actually good block :)))
+			uffs_Perror(UFFS_ERR_NOISY, "new bad block %d found, and replaced by %d!", dev->bad.block, good->u.list.block);
+			uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+			//we reuse the 'good' node as bad block node, and process the bad block.
+			good->u.list.block = dev->bad.block;
+			uffs_BadBlockProcess(dev, good);
+		}
+		else {
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't find the reported bad block(%d) in the tree???", dev->bad.block);
+			if (goodBlockIsDirty == U_TRUE)
+				dev->ops->EraseBlock(dev, good->u.list.block);
+			uffs_TreeInsertToErasedListTail(dev, good);
+		}
+	}
+	else {
+		if (goodBlockIsDirty == U_TRUE)
+			dev->ops->EraseBlock(dev, good->u.list.block);
+		uffs_TreeInsertToErasedListTail(dev, good); //put back to erased list
+	}
+	type = type;
+	uffs_BlockInfoPut(dev, bc);
+
 }
 
 
-/** put a new block to the bad block waiting list */
-void uffs_BadBlockAdd(uffs_Device *dev, int block)
-{
-	if (dev->bad.block == block)
-		return;
-
-	if (dev->bad.block != UFFS_INVALID_BLOCK)
-		uffs_Perror(UFFS_ERR_SERIOUS, "Can't add more then one bad block !");
-	else
-		dev->bad.block = block;
-}
-
+/** put a new block to the bad block waiting list */
+void uffs_BadBlockAdd(uffs_Device *dev, int block)
+{
+	if (dev->bad.block == block)
+		return;
+
+	if (dev->bad.block != UFFS_INVALID_BLOCK)
+		uffs_Perror(UFFS_ERR_SERIOUS, "Can't add more then one bad block !");
+	else
+		dev->bad.block = block;
+}
+

+ 302 - 302
components/dfs/filesystems/uffs/src/uffs/uffs_blockinfo.c

@@ -1,33 +1,33 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
 */
 
 /**
@@ -40,9 +40,9 @@
 #include "uffs/uffs_public.h"
 #include "uffs/uffs_os.h"
 
-#include <string.h>
+#include <rtthread.h>
 
-#define PFX "bc  : "
+#define PFX "bc:   "
 
 #define UFFS_CLONE_BLOCK_INFO_NEXT ((uffs_BlockInfo *)(-2))
 
@@ -52,86 +52,86 @@
  * \param[in] dev uffs device
  * \param[in] maxCachedBlocks maximum cache buffers to be allocated
  * \return result of initialization
- *		\retval U_SUCC successful
- *		\retval U_FAIL failed
+ *		\retval RT_EOK successful
+ *		\retval RT_ERROR failed
  */
-URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks)
-{
-	uffs_BlockInfo * blockInfos = NULL;
-	uffs_PageSpare * pageSpares = NULL;
-	void * buf = NULL;
-	uffs_BlockInfo *work = NULL;
-	int size, i, j;
-
-	if (dev->bc.head != NULL) {
-		uffs_Perror(UFFS_ERR_NOISY, "block info cache has been inited already, now release it first.");
-		uffs_BlockInfoReleaseCache(dev);
-	}
-
-	size = ( 
-			sizeof(uffs_BlockInfo) +
-			sizeof(uffs_PageSpare) * dev->attr->pages_per_block
-			) * maxCachedBlocks;
-
-	if (dev->mem.blockinfo_pool_size == 0) {
-		if (dev->mem.malloc) {
-			dev->mem.blockinfo_pool_buf = dev->mem.malloc(dev, size);
-			if (dev->mem.blockinfo_pool_buf) dev->mem.blockinfo_pool_size = size;
-		}
-	}
-	if (size > dev->mem.blockinfo_pool_size) {
-		uffs_Perror(UFFS_ERR_DEAD, "Block cache buffer require %d but only %d available.", size, dev->mem.blockinfo_pool_size);
-		return U_FAIL;
-	}
-
-	uffs_Perror(UFFS_ERR_NOISY, "alloc info cache %d bytes.", size);
-
-	buf = dev->mem.blockinfo_pool_buf;
-
-	memset(buf, 0, size);
-
-	dev->bc.mem_pool = buf;
-
-	size = 0;
-	blockInfos = (uffs_BlockInfo *)buf;
-	size += sizeof(uffs_BlockInfo) * maxCachedBlocks;
-
-	pageSpares = (uffs_PageSpare *)((char *)buf + size);
-
-	//initialize block info
-	work = &(blockInfos[0]);
-	dev->bc.head = work;
-	work->ref_count = 0;
-	work->prev = NULL;
-	work->next = &(blockInfos[1]);
-	work->block = UFFS_INVALID_BLOCK;
-
-	for (i = 0; i < maxCachedBlocks - 2; i++) {
-		work = &(blockInfos[i+1]);
-		work->prev = &(blockInfos[i]);
-		work->next = &(blockInfos[i+2]);
-		work->ref_count = 0;
-		work->block = UFFS_INVALID_BLOCK;
-	}
-	//the last node
-	work = &(blockInfos[i+1]);
-	work->prev = &(blockInfos[i]);
-	work->next = NULL;
-	work->block = UFFS_INVALID_BLOCK;
-	work->ref_count = 0;
-	dev->bc.tail = work;
-
-	//initialize spares
-	work = dev->bc.head;
-	for (i = 0; i < maxCachedBlocks; i++) {
-		work->spares = &(pageSpares[i*dev->attr->pages_per_block]);
-		for (j = 0; j < dev->attr->pages_per_block; j++) {
-			work->spares[j].expired = 1;
-		}
-		work->expired_count = dev->attr->pages_per_block;
-		work = work->next;
-	}
-	return U_SUCC;
+URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks)
+{
+	uffs_BlockInfo * blockInfos = NULL;
+	uffs_PageSpare * pageSpares = NULL;
+	void * buf = NULL;
+	uffs_BlockInfo *work = NULL;
+	int size, i, j;
+
+	if (dev->bc.head != NULL) {
+		uffs_Perror(UFFS_ERR_NOISY, "block info cache has been inited already, now release it first.");
+		uffs_BlockInfoReleaseCache(dev);
+	}
+
+	size = ( 
+			sizeof(uffs_BlockInfo) +
+			sizeof(uffs_PageSpare) * dev->attr->pages_per_block
+			) * maxCachedBlocks;
+
+	if (dev->mem.blockinfo_pool_size == 0) {
+		if (dev->mem.malloc) {
+			dev->mem.blockinfo_pool_buf = dev->mem.malloc(dev, size);
+			if (dev->mem.blockinfo_pool_buf) dev->mem.blockinfo_pool_size = size;
+		}
+	}
+	if (size > dev->mem.blockinfo_pool_size) {
+		uffs_Perror(UFFS_ERR_DEAD, "Block cache buffer require %d but only %d available.", size, dev->mem.blockinfo_pool_size);
+		return U_FAIL;
+	}
+
+	uffs_Perror(UFFS_ERR_NOISY, "alloc info cache %d bytes.", size);
+
+	buf = dev->mem.blockinfo_pool_buf;
+
+	memset(buf, 0, size);
+
+	dev->bc.mem_pool = buf;
+
+	size = 0;
+	blockInfos = (uffs_BlockInfo *)buf;
+	size += sizeof(uffs_BlockInfo) * maxCachedBlocks;
+
+	pageSpares = (uffs_PageSpare *)((char *)buf + size);
+
+	//initialize block info
+	work = &(blockInfos[0]);
+	dev->bc.head = work;
+	work->ref_count = 0;
+	work->prev = NULL;
+	work->next = &(blockInfos[1]);
+	work->block = UFFS_INVALID_BLOCK;
+
+	for (i = 0; i < maxCachedBlocks - 2; i++) {
+		work = &(blockInfos[i+1]);
+		work->prev = &(blockInfos[i]);
+		work->next = &(blockInfos[i+2]);
+		work->ref_count = 0;
+		work->block = UFFS_INVALID_BLOCK;
+	}
+	//the last node
+	work = &(blockInfos[i+1]);
+	work->prev = &(blockInfos[i]);
+	work->next = NULL;
+	work->block = UFFS_INVALID_BLOCK;
+	work->ref_count = 0;
+	dev->bc.tail = work;
+
+	//initialize spares
+	work = dev->bc.head;
+	for (i = 0; i < maxCachedBlocks; i++) {
+		work->spares = &(pageSpares[i*dev->attr->pages_per_block]);
+		for (j = 0; j < dev->attr->pages_per_block; j++) {
+			work->spares[j].expired = 1;
+		}
+		work->expired_count = dev->attr->pages_per_block;
+		work = work->next;
+	}
+	return U_SUCC;
 }
 
 /**
@@ -139,55 +139,55 @@ URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks)
  *			this function should be called when unmount file system
  * \param[in] dev uffs device
  */
-URET uffs_BlockInfoReleaseCache(uffs_Device *dev)
-{
-	uffs_BlockInfo *work;
-
-	if (dev->bc.head) {
-		for (work = dev->bc.head; work != NULL; work = work->next) {
-			if (work->ref_count != 0) {
-				uffs_Perror(UFFS_ERR_SERIOUS,  "There have refed block info cache, release cache fail.");
-				return U_FAIL;
-			}
-		}
-		if (dev->mem.free) {
-			dev->mem.free(dev, dev->bc.mem_pool);
-		}
-	}
-
-	dev->bc.head = dev->bc.tail = NULL;
-	dev->bc.mem_pool = NULL;
-
-	return U_SUCC;
-}
-
-static void _BreakBcFromList(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	if (bc->prev)
-		bc->prev->next = bc->next;
-
-	if (bc->next)
-		bc->next->prev = bc->prev;
-
-	if (dev->bc.head == bc)
-		dev->bc.head = bc->next;
-
-	if (dev->bc.tail == bc)
-		dev->bc.tail = bc->prev;
-}
-
-static void _InsertToBcListTail(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	bc->next = NULL;
-	bc->prev = dev->bc.tail;
-	bc->prev->next = bc;
-	dev->bc.tail = bc;
-}
-
-static void _MoveBcToTail(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	_BreakBcFromList(dev, bc);
-	_InsertToBcListTail(dev, bc);
+URET uffs_BlockInfoReleaseCache(uffs_Device *dev)
+{
+	uffs_BlockInfo *work;
+
+	if (dev->bc.head) {
+		for (work = dev->bc.head; work != NULL; work = work->next) {
+			if (work->ref_count != 0) {
+				uffs_Perror(UFFS_ERR_SERIOUS,  "There have refed block info cache, release cache fail.");
+				return U_FAIL;
+			}
+		}
+		if (dev->mem.free) {
+			dev->mem.free(dev, dev->bc.mem_pool);
+		}
+	}
+
+	dev->bc.head = dev->bc.tail = NULL;
+	dev->bc.mem_pool = NULL;
+
+	return U_SUCC;
+}
+
+static void _BreakBcFromList(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	if (bc->prev)
+		bc->prev->next = bc->next;
+
+	if (bc->next)
+		bc->next->prev = bc->prev;
+
+	if (dev->bc.head == bc)
+		dev->bc.head = bc->next;
+
+	if (dev->bc.tail == bc)
+		dev->bc.tail = bc->prev;
+}
+
+static void _InsertToBcListTail(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	bc->next = NULL;
+	bc->prev = dev->bc.tail;
+	bc->prev->next = bc;
+	dev->bc.tail = bc;
+}
+
+static void _MoveBcToTail(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	_BreakBcFromList(dev, bc);
+	_InsertToBcListTail(dev, bc);
 }
 
 
@@ -195,50 +195,50 @@ static void _MoveBcToTail(uffs_Device *dev, uffs_BlockInfo *bc)
  * \brief load page spare data to given block info structure with given page number
  * \param[in] dev uffs device
  * \param[in] work given block info to be filled with
- * \param[in] page given page number to be read from, if #UFFS_ALL_PAGES is presented, it will read
+ * \param[in] page given page number to be read from, if#UFFS_ALL_PAGES is presented, it will read
  *			all pages, otherwise it will read only one given page.
  * \return load result
- * \retval U_SUCC successful
- * \retval U_FAIL fail to load
+ * \retval RT_EOK successful
+ * \retval RT_ERROR fail to load
  * \note work->block must be set before load block info
  */
-URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page)
-{
-	int i, ret;
-	uffs_PageSpare *spare;
-
-	if (page == UFFS_ALL_PAGES) {
-		for (i = 0; i < dev->attr->pages_per_block; i++) {
-			spare = &(work->spares[i]);
-			if (spare->expired == 0)
-				continue;
-			
-			ret = uffs_FlashReadPageSpare(dev, work->block, i, &(spare->tag), NULL);
-			if (UFFS_FLASH_HAVE_ERR(ret)) {
-				uffs_Perror(UFFS_ERR_SERIOUS,  "load block %d page %d spare fail.", work->block, i);
-				return U_FAIL;
-			}
-			spare->expired = 0;
-			work->expired_count--;
-		}
-	}
-	else {
-		if (page < 0 || page >= dev->attr->pages_per_block) {
-			uffs_Perror(UFFS_ERR_SERIOUS,  "page out of range !");
-			return U_FAIL;
-		}
-		spare = &(work->spares[page]);
-		if (spare->expired != 0) {
-			ret = uffs_FlashReadPageSpare(dev, work->block, page, &(spare->tag), NULL);
-			if (UFFS_FLASH_HAVE_ERR(ret)) {
-				uffs_Perror(UFFS_ERR_SERIOUS,  "load block %d page %d spare fail.", work->block, page);
-				return U_FAIL;
-			}
-			spare->expired = 0;
-			work->expired_count--;
-		}
-	}
-	return U_SUCC;
+URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page)
+{
+	int i, ret;
+	uffs_PageSpare *spare;
+
+	if (page == UFFS_ALL_PAGES) {
+		for (i = 0; i < dev->attr->pages_per_block; i++) {
+			spare = &(work->spares[i]);
+			if (spare->expired == 0)
+				continue;
+			
+			ret = uffs_FlashReadPageSpare(dev, work->block, i, &(spare->tag), NULL);
+			if (UFFS_FLASH_HAVE_ERR(ret)) {
+				uffs_Perror(UFFS_ERR_SERIOUS,  "load block %d page %d spare fail.", work->block, i);
+				return U_FAIL;
+			}
+			spare->expired = 0;
+			work->expired_count--;
+		}
+	}
+	else {
+		if (page < 0 || page >= dev->attr->pages_per_block) {
+			uffs_Perror(UFFS_ERR_SERIOUS,  "page out of range !");
+			return U_FAIL;
+		}
+		spare = &(work->spares[page]);
+		if (spare->expired != 0) {
+			ret = uffs_FlashReadPageSpare(dev, work->block, page, &(spare->tag), NULL);
+			if (UFFS_FLASH_HAVE_ERR(ret)) {
+				uffs_Perror(UFFS_ERR_SERIOUS,  "load block %d page %d spare fail.", work->block, page);
+				return U_FAIL;
+			}
+			spare->expired = 0;
+			work->expired_count--;
+		}
+	}
+	return U_SUCC;
 }
 
 
@@ -250,18 +250,18 @@ URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page)
  * \retval NULL cache not found
  * \retval non-NULL found cache pointer
  */
-uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block)
-{
-	uffs_BlockInfo *work;
-	
-	//search cached block
-	for (work = dev->bc.head; work != NULL; work = work->next) {
-		if (work->block == block) {
-			work->ref_count++;
-			return work;
-		}
-	}
-	return NULL;
+uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block)
+{
+	uffs_BlockInfo *work;
+	
+	//search cached block
+	for (work = dev->bc.head; work != NULL; work = work->next) {
+		if (work->block == block) {
+			work->ref_count++;
+			return work;
+		}
+	}
+	return NULL;
 }
 
 
@@ -275,38 +275,38 @@ uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block)
  * \retval NULL caches used out
  * \retval non-NULL buffer pointer of given block
  */
-uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block)
-{
-	uffs_BlockInfo *work;
-	int i;
-
-	//search cached block
-	if ((work = uffs_BlockInfoFindInCache(dev, block)) != NULL) {
-		_MoveBcToTail(dev, work);
-		return work;
-	}
-
-	//can't find block from cache, need to find a free(unlocked) cache
-	for (work = dev->bc.head; work != NULL; work = work->next) {
-		if(work->ref_count == 0) break;
-	}
-	if (work == NULL) {
-		//caches used out !
-		uffs_Perror(UFFS_ERR_SERIOUS,  "insufficient block info cache");
-		return NULL;
-	}
-
-	work->block = block;
-	work->expired_count = dev->attr->pages_per_block;
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		work->spares[i].expired = 1;
-	}
-
-	work->ref_count = 1;
-
-	_MoveBcToTail(dev, work);
-
-	return work;
+uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block)
+{
+	uffs_BlockInfo *work;
+	int i;
+
+	//search cached block
+	if ((work = uffs_BlockInfoFindInCache(dev, block)) != NULL) {
+		_MoveBcToTail(dev, work);
+		return work;
+	}
+
+	//can't find block from cache, need to find a free(unlocked) cache
+	for (work = dev->bc.head; work != NULL; work = work->next) {
+		if(work->ref_count == 0) break;
+	}
+	if (work == NULL) {
+		//caches used out !
+		uffs_Perror(UFFS_ERR_SERIOUS,  "insufficient block info cache");
+		return NULL;
+	}
+
+	work->block = block;
+	work->expired_count = dev->attr->pages_per_block;
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		work->spares[i].expired = 1;
+	}
+
+	work->ref_count = 1;
+
+	_MoveBcToTail(dev, work);
+
+	return work;
 }
 
 /** 
@@ -314,15 +314,15 @@ uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block)
  * \param[in] dev uffs device
  * \param[in] p pointer of block info buffer
  */
-void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p)
-{
-	dev = dev;
-	if (p->ref_count == 0) {
-		uffs_Perror(UFFS_ERR_SERIOUS,  "Put an unused block info cache back ?");
-	}
-	else {
-		p->ref_count--;
-	}
+void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p)
+{
+	dev = dev;
+	if (p->ref_count == 0) {
+		uffs_Perror(UFFS_ERR_SERIOUS,  "Put an unused block info cache back ?");
+	}
+	else {
+		p->ref_count--;
+	}
 }
 
 
@@ -330,58 +330,58 @@ void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p)
  * \brief make the given pages expired in given block info buffer
  * \param[in] dev uffs device
  * \param[in] p pointer of block info buffer
- * \param[in] page given page number. if #UFFS_ALL_PAGES presented, all pages in the block should be made expired.
+ * \param[in] page given page number. if#UFFS_ALL_PAGES presented, all pages in the block should be made expired.
  */
-void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page)
-{
-	int i;
-	uffs_PageSpare *spare;
-
-	if (page == UFFS_ALL_PAGES) {
-		for (i = 0; i < dev->attr->pages_per_block; i++) {
-			spare = &(p->spares[i]);
-			if (spare->expired == 0) {
-				spare->expired = 1;
-				p->expired_count++;
-			}
-		}
-	}
-	else {
-		if (page >= 0 && page < dev->attr->pages_per_block) {
-			spare = &(p->spares[page]);
-			if (spare->expired == 0) {
-				spare->expired = 1;
-				p->expired_count++;
-			}
-		}
-	}
+void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page)
+{
+	int i;
+	uffs_PageSpare *spare;
+
+	if (page == UFFS_ALL_PAGES) {
+		for (i = 0; i < dev->attr->pages_per_block; i++) {
+			spare = &(p->spares[i]);
+			if (spare->expired == 0) {
+				spare->expired = 1;
+				p->expired_count++;
+			}
+		}
+	}
+	else {
+		if (page >= 0 && page < dev->attr->pages_per_block) {
+			spare = &(p->spares[page]);
+			if (spare->expired == 0) {
+				spare->expired = 1;
+				p->expired_count++;
+			}
+		}
+	}
 }
 
 /** 
  * Is all blcok info cache free (not referenced) ?
  */
-UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev)
-{
-	uffs_BlockInfo *work;
-
-	work = dev->bc.head;
-	while (work) {
-		if (work->ref_count != 0)
-			return U_FALSE;
-		work = work->next;
-	}
-
-	return U_TRUE;
-}
-
-void uffs_BlockInfoExpireAll(uffs_Device *dev)
-{
-	uffs_BlockInfo *bc;
-
-	bc = dev->bc.head;
-	while (bc) {
-		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-		bc = bc->next;
-	}
-	return;
-}
+UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev)
+{
+	uffs_BlockInfo *work;
+
+	work = dev->bc.head;
+	while (work) {
+		if (work->ref_count != 0)
+			return U_FALSE;
+		work = work->next;
+	}
+
+	return U_TRUE;
+}
+
+void uffs_BlockInfoExpireAll(uffs_Device *dev)
+{
+	uffs_BlockInfo *bc;
+
+	bc = dev->bc.head;
+	while (bc) {
+		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+		bc = bc->next;
+	}
+	return;
+}

+ 1591 - 1591
components/dfs/filesystems/uffs/src/uffs/uffs_buf.c

@@ -1,1591 +1,1591 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-/** 
- * \file uffs_buf.c
- * \brief uffs page buffers manipulations
- * \author Ricky Zheng
- * \note Created in 11th May, 2005
- */
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_buf.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_pool.h"
-#include "uffs/uffs_ecc.h"
-#include "uffs/uffs_badblock.h"
-#include <string.h>
-
-#define PFX "pbuf: "
-
-
-URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot);
-
-
-/**
- * \brief inspect (print) uffs page buffers.
- * \param[in] dev uffs device to be inspected.
- */
-void uffs_BufInspect(uffs_Device *dev)
-{
-	struct uffs_PageBufDescSt *pb = &dev->buf;
-	uffs_Buf *buf;
-
-	uffs_PerrorRaw(UFFS_ERR_NORMAL, "------------- page buffer inspect ---------" TENDSTR);
-	uffs_PerrorRaw(UFFS_ERR_NORMAL, "all buffers: " TENDSTR);
-	for (buf = pb->head; buf; buf = buf->next) {
-		if (buf->mark != 0) {
-			uffs_PerrorRaw(UFFS_ERR_NORMAL, "\tF:%04x S:%04x P:%02d R:%02d D:%03d M:%c EM:%d"  TENDSTR, 
-				buf->parent, buf->serial, buf->page_id, buf->ref_count, buf->data_len, buf->mark == UFFS_BUF_VALID ? 'V' : 'D', buf->ext_mark);
-		}
-	}
-	uffs_PerrorRaw(UFFS_ERR_NORMAL, "--------------------------------------------"  TENDSTR);
-}
-
-/**
- * \brief initialize page buffers for device
- * in UFFS, each device has one buffer pool
- * \param[in] dev uffs device
- * \param[in] buf_max maximum buffer number, normally use #MAX_PAGE_BUFFERS
- * \param[in] dirty_buf_max maximum dirty buffer allowed, if the dirty buffer over this number,
- *            than need to be flush to flash
- */
-URET uffs_BufInit(uffs_Device *dev, int buf_max, int dirty_buf_max)
-{
-	void *pool;
-	u8 *data;
-	uffs_Buf *buf;
-	int size;
-	int i, slot;
-
-	if (!dev)
-		return U_FAIL;
-
-	//init device common parameters, which are needed by page buffers
-	dev->com.pg_size = dev->attr->page_data_size;  // we use the whole page.
-	dev->com.header_size = sizeof(struct uffs_MiniHeaderSt);	// mini header
-	dev->com.pg_data_size = dev->com.pg_size - dev->com.header_size;
-
-	if (dev->buf.pool != NULL) {
-		uffs_Perror(UFFS_ERR_NORMAL, "buf.pool is not NULL, buf already inited ?");
-		return U_FAIL;
-	}
-	
-	size = (sizeof(uffs_Buf) + dev->com.pg_size) * buf_max;
-	if (dev->mem.pagebuf_pool_size == 0) {
-		if (dev->mem.malloc) {
-			dev->mem.pagebuf_pool_buf = dev->mem.malloc(dev, size);
-			if (dev->mem.pagebuf_pool_buf)
-				dev->mem.pagebuf_pool_size = size;
-		}
-	}
-	if (size > dev->mem.pagebuf_pool_size) {
-		uffs_Perror(UFFS_ERR_DEAD, "page buffers require %d but only %d available.", size, dev->mem.pagebuf_pool_size);
-		return U_FAIL;
-	}
-	pool = dev->mem.pagebuf_pool_buf;
-
-	uffs_Perror(UFFS_ERR_NOISY, "alloc %d bytes.", size);
-	dev->buf.pool = pool;
-
-	for (i = 0; i < buf_max; i++) {
-		buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
-		memset(buf, 0, sizeof(uffs_Buf));
-		data = (u8 *)pool + (sizeof(uffs_Buf) * buf_max) + (dev->com.pg_size * i);
-		buf->header = data;
-		buf->data = data + dev->com.header_size;
-		buf->mark = UFFS_BUF_EMPTY;
-		memset(buf->header, 0, dev->com.pg_size);
-		if (i == 0) {
-			buf->prev = NULL;
-			dev->buf.head = buf;
-		}
-		else {
-			buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
-		}
-
-		if (i == (buf_max - 1)) {
-			buf->next = NULL;
-			dev->buf.tail = buf;
-		}
-		else {
-			buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
-		}
-	}
-
-	dev->buf.buf_max = buf_max;
-	dev->buf.dirty_buf_max = (dirty_buf_max > dev->attr->pages_per_block ? dev->attr->pages_per_block : dirty_buf_max);
-
-	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
-		dev->buf.dirtyGroup[slot].dirty = NULL;
-		dev->buf.dirtyGroup[slot].count = 0;
-	}
-	return U_SUCC;
-}
-
-/**
- * \brief flush all buffers
- */
-URET uffs_BufFlushAll(struct uffs_DeviceSt *dev)
-{
-	int slot;
-	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
-		if(_BufFlush(dev, FALSE, slot) != U_SUCC) {
-			uffs_Perror(UFFS_ERR_NORMAL, "fail to flush buffer(slot %d)", slot);
-			return U_FAIL;
-		}
-	}
-	return U_SUCC;
-}
-
-/** 
- * \brief release all page buffer, this function should be called 
-			when unmounting a uffs device
- * \param[in] dev uffs device
- * \note if there are page buffers in used, it may cause fail to release
- */
-URET uffs_BufReleaseAll(uffs_Device *dev)
-{
-	uffs_Buf *p;
-
-	if (!dev)
-		return U_FAIL;
-
-	//now release all buffer
-	p = dev->buf.head;
-	while (p) {
-		if (p->ref_count != 0) {
-			uffs_Perror(UFFS_ERR_NORMAL, 
-				PFX "can't release buffers, \
-					parent:%d, serial:%d, page_id:%d still in used.\n", p->parent, p->serial, p->page_id);
-			return U_FAIL;
-		}
-		p = p->next;
-	}
-
-	if (uffs_BufFlushAll(dev) != U_SUCC) {
-		uffs_Perror(UFFS_ERR_NORMAL, "can't release buf, fail to flush buffer");
-		return U_FAIL;
-	}
-
-	if (dev->mem.free)
-		dev->mem.free(dev, dev->buf.pool);
-
-	dev->buf.pool = NULL;
-	dev->buf.head = dev->buf.tail = NULL;
-
-	return U_SUCC;
-}
-
-
-static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
-{
-	if(buf->next)
-		buf->next->prev = buf->prev;
-
-	if(buf->prev)
-		buf->prev->next = buf->next;
-
-	if(dev->buf.head == buf)
-		dev->buf.head = buf->next;
-
-	if(dev->buf.tail == buf)
-		dev->buf.tail = buf->prev;
-
-}
-
-static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
-{
-	if (buf == dev->buf.head)
-		return;
-
-	buf->prev = NULL;
-	buf->next = dev->buf.head;
-
-	if (dev->buf.head)
-		dev->buf.head->prev = buf;
-
-	if (dev->buf.tail == NULL)
-		dev->buf.tail = buf;
-
-	dev->buf.head = buf;
-}
-
-static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
-{
-	if (dev->buf.tail == buf)
-		return;
-
-	buf->prev = dev->buf.tail;
-	buf->next = NULL;
-
-	if (dev->buf.tail)
-		dev->buf.tail->next = buf;
-
-	if (dev->buf.head == NULL)
-		dev->buf.head = buf;
-
-	dev->buf.tail = buf;
-}
-
-//move a node which linked in the list to the head of list
-static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
-{
-	if (p == dev->buf.head)
-		return;
-
-	//break from list
-	_BreakFromBufList(dev, p);
-
-	//link to head
-	_LinkToBufListHead(dev, p);
-}
-
-// check if the buf is already in dirty list
-static UBOOL _IsBufInInDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
-{
-	uffs_Buf *work;
-	work = dev->buf.dirtyGroup[slot].dirty;
-	while (work) {
-		if (work == buf) 
-			return U_TRUE;
-		work = work->next_dirty;
-	}
-
-	return U_FALSE;
-}
-
-static void _LinkToDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
-{
-
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Try to insert a NULL node into dirty list ?");
-		return;
-	}
-
-	buf->mark = UFFS_BUF_DIRTY;
-	buf->prev_dirty = NULL;
-	buf->next_dirty = dev->buf.dirtyGroup[slot].dirty;
-
-	if (dev->buf.dirtyGroup[slot].dirty) 
-		dev->buf.dirtyGroup[slot].dirty->prev_dirty = buf;
-
-	dev->buf.dirtyGroup[slot].dirty = buf;
-	dev->buf.dirtyGroup[slot].count++;
-}
-
-static int CountFreeBuf(uffs_Device *dev)
-{
-	int count = 0;
-
-	uffs_Buf *buf = dev->buf.head;
-
-	while (buf) {
-
-		if (buf->ref_count == 0 && 
-			buf->mark != UFFS_BUF_DIRTY)
-			count++;
-
-		buf = buf->next;
-	}
-
-	return count;
-}
-
-static uffs_Buf * _FindFreeBufEx(uffs_Device *dev, int clone)
-{
-	uffs_Buf *buf;
-
-	if (!clone && CountFreeBuf(dev) <= CLONE_BUFFERS_THRESHOLD)
-		return NULL;
-
-#if 1
-	buf = dev->buf.head;
-	while (buf) {
-
-		if (buf->ref_count == 0 && 
-			buf->mark != UFFS_BUF_DIRTY)
-			return buf;
-
-		buf = buf->next;
-	}
-#else
-	buf = dev->buf.tail;
-	while (buf) {
-
-		if(buf->ref_count == 0 &&
-			buf->mark != UFFS_BUF_DIRTY) 
-			return buf;
-
-		buf = buf->prev;
-	}
-#endif
-
-	return buf;
-}
-
-static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
-{
-	return _FindFreeBufEx(dev, 0);
-}
-
-
-/** 
- * load psychical page data into buf and do ecc check 
- * \param[in] dev uffs device
- * \param[in] buf buf to be load in
- * \param[in] block psychical block number
- * \param[in] page psychical page number
- * \return return U_SUCC if no error, return U_FAIL if I/O error or ecc check fail
- */
-URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
-{
-	int ret;
-
-	ret = uffs_FlashReadPage(dev, block, page, buf);
-
-	if (UFFS_FLASH_HAVE_ERR(ret)) {
-		buf->mark = UFFS_BUF_EMPTY;
-		return U_FAIL;
-	}
-	else {
-		buf->mark = UFFS_BUF_VALID;
-		return U_SUCC;
-	}
-}
-
-/** 
- * \brief load psychical page data into buf and ignore ECC result
- *
- * \param[in] dev uffs device
- * \param[in] buf buf to be load in
- * \param[in] block psychical block number
- * \param[in] page psychical page number
- *
- * \return return U_SUCC if no error, return U_FAIL if I/O error
- * \note this function should be only used when doing bad block recover.
- */
-URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
-{
-	int ret;
-
-	ret = uffs_FlashReadPage(dev, block, page, buf);
-
-	if (ret == UFFS_FLASH_IO_ERR) {
-		buf->mark = UFFS_BUF_EMPTY;
-		return U_FAIL;
-	}
-	else {
-		buf->mark = UFFS_BUF_VALID;
-		return U_SUCC;
-	}
-}
-
-
-/** 
- * find a buffer in the pool
- * \param[in] dev uffs device
- * \param[in] parent parent serial num
- * \param[in] serial serial num
- * \param[in] page_id page_id
- * \return return found buffer, return NULL if buffer not found
- */
-uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 parent, u16 serial, u16 page_id)
-{
-	uffs_Buf *p = dev->buf.head;
-
-	while (p) {
-		if(	p->parent == parent &&
-			p->serial == serial &&
-			p->page_id == page_id &&
-			p->mark != UFFS_BUF_EMPTY) 
-		{
-			//they have match one
-			return p;
-		}
-		p = p->next;
-	}
-
-	return NULL; //buffer not found
-}
-
-static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 page_id)
-{
-	while(dirty) {
-		if (dirty->page_id == page_id) 
-			return dirty;
-		dirty = dirty->next_dirty;
-	}
-	return NULL;
-}
-
-static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
-{
-	int slot = -1;
-
-	if (dirtyBuf->mark != UFFS_BUF_DIRTY) {
-		uffs_Perror(UFFS_ERR_NORMAL, "try to break a non-dirty buf from dirty list ?");
-		return U_FAIL;
-	}
-
-	slot = uffs_BufFindGroupSlot(dev, dirtyBuf->parent, dirtyBuf->serial);
-	if (slot < 0) {
-		uffs_Perror(UFFS_ERR_NORMAL, "no dirty list exit ?");
-		return U_FAIL;
-	}
-
-	// break from the link
-	if (dirtyBuf->next_dirty) {
-		dirtyBuf->next_dirty->prev_dirty = dirtyBuf->prev_dirty;
-	}
-
-	if (dirtyBuf->prev_dirty) {
-		dirtyBuf->prev_dirty->next_dirty = dirtyBuf->next_dirty;
-	}
-
-	// check if it's the link head ...
-	if (dev->buf.dirtyGroup[slot].dirty == dirtyBuf) {
-		dev->buf.dirtyGroup[slot].dirty = dirtyBuf->next_dirty;
-	}
-
-	dirtyBuf->next_dirty = dirtyBuf->prev_dirty = NULL; // clear dirty link
-
-	dev->buf.dirtyGroup[slot].count--;
-
-	return U_SUCC;
-}
-
-static u16 _GetDirOrFileNameSum(uffs_Device *dev, uffs_Buf *buf)
-{
-	u16 data_sum = 0; //default: 0
-	uffs_FileInfo *fi;
-	
-	dev = dev;
-	//FIXME: We use the same schema for both dir and file.
-	if (buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
-		if (buf->page_id == 0) {
-			fi = (uffs_FileInfo *)(buf->data);
-			data_sum = uffs_MakeSum16(fi->name, fi->name_len);
-		}
-	}
-
-	return data_sum;
-}
-
-
-static URET _CheckDirtyList(uffs_Buf *dirty)
-{
-	u16 parent;
-	u16 serial;
-
-	if (dirty == NULL) {
-		return U_SUCC;
-	}
-
-	parent = dirty->parent;
-	serial = dirty->serial;
-	dirty = dirty->next_dirty;
-
-	while (dirty) {
-		if (parent != dirty->parent ||
-			serial != dirty->serial) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "parent or serial in dirty pages buffer are not the same ?");
-			return U_FAIL;
-		}
-		if (dirty->mark != UFFS_BUF_DIRTY) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "non-dirty page buffer in dirty buffer list ?");
-			return U_FAIL;
-		}
-		dirty = dirty->next_dirty;
-	}
-	return U_SUCC;
-}
-
-/** find a page in dirty list, which has minimum page_id */
-uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
-{
-	uffs_Buf * work = dirtyList;
-	uffs_Buf * buf = dirtyList;
-
-	work = work->next_dirty;
-	while (work) {
-		if (work->page_id < buf->page_id)
-			buf = work;
-		work = work->next_dirty;
-	}
-	return buf;
-}
-
-
-/** 
- * \brief flush buffer with block recover
- *
- * Scenario: 
- *		1. get a free (erased) block --> newNode <br>
- *		2. copy from old block ---> oldNode, or copy from dirty list, <br>
- *			sorted by page_id, to new block. Skips the invalid pages when copy pages.<br>
- *		3. erased old block. set new info to oldNode, set newNode->block = old block,<br>
- *			and put newNode to erased list.<br>
- *	\note IT'S IMPORTANT TO KEEP OLD NODE IN THE LIST, so you don't need to update the obj->node :-)
- */
-static URET uffs_BufFlush_Exist_With_BlockCover(
-			uffs_Device *dev,
-			int slot,			//!< dirty group slot
-			TreeNode *node,		//!< old data node on tree
-			uffs_BlockInfo *bc	//!< old data block info
-			)
-{
-	u16 i;
-	u8 type, timeStamp;
-	u16 page, parent, serial;
-	uffs_Buf *buf;
-	TreeNode *newNode;
-	uffs_BlockInfo *newBc;
-	uffs_Tags *tag, *oldTag;
-	int x;
-	u16 newBlock;
-	UBOOL succRecover;			//U_TRUE: recover successful, erase old block,
-								//U_FALSE: fail to recover, erase new block
-	UBOOL flash_op_err;
-	u16 data_sum;
-
-	type = dev->buf.dirtyGroup[slot].dirty->type;
-	parent = dev->buf.dirtyGroup[slot].dirty->parent;
-	serial = dev->buf.dirtyGroup[slot].dirty->serial;
-
-retry:
-	flash_op_err = UFFS_FLASH_NO_ERR;
-	succRecover = U_FALSE;
-
-	newNode = uffs_TreeGetErasedNode(dev);
-	if (newNode == NULL) {
-		uffs_Perror(UFFS_ERR_NOISY, "no enough erased block!");
-		goto ext;
-	}
-	newBlock = newNode->u.list.block;
-	newBc = uffs_BlockInfoGet(dev, newBlock);
-	if (newBc == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail!");
-		uffs_InsertToErasedListHead(dev, newNode);  //put node back to erased list
-													//because it doesn't use, so put to head
-		goto ext;
-	}
-
-	uffs_BlockInfoLoad(dev, newBc, UFFS_ALL_PAGES);
-	timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));
-
-//	uffs_Perror(UFFS_ERR_NOISY, "Flush buffers with Block Recover, from %d to %d", 
-//					bc->block, newBc->block);
-
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		tag = GET_TAG(newBc, i);
-		TAG_BLOCK_TS(tag) = timeStamp;
-		TAG_PARENT(tag) = parent;
-		TAG_SERIAL(tag) = serial;
-		TAG_TYPE(tag) = type;
-		TAG_PAGE_ID(tag) = (u8)i; //now, page_id = page, FIX ME!! if more than 256 pages in a block
-		
-		buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
-		if (buf != NULL) {
-			if (i == 0)
-				data_sum = _GetDirOrFileNameSum(dev, buf);
-
-			TAG_DATA_LEN(tag) = buf->data_len;
-
-			if (buf->data_len == 0) // this could happen when truncating a file
-				flash_op_err = UFFS_FLASH_NO_ERR;
-			else
-				flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
-
-			if (flash_op_err == UFFS_FLASH_BAD_BLK) {
-				uffs_Perror(UFFS_ERR_NORMAL, "new bad block %d discovered.", newBlock);
-				break;
-			}
-			else if (flash_op_err == UFFS_FLASH_IO_ERR) {
-				uffs_Perror(UFFS_ERR_NORMAL, "writing to block %d page %d, I/O error ?", (int)newBlock, (int)i);
-				break;
-			}
-			else if (buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL) {
-				// when truncating a file, the last dirty buf will be set as UFFS_BUF_EXT_MARK_TAIL.
-				// so that we don't do page recovery for the rest pages in the block.
-				uffs_BlockInfoExpire(dev, newBc, i);
-				succRecover = U_TRUE;
-				break;
-			}
-		}
-		else {
-			page = uffs_FindPageInBlockWithPageId(dev, bc, i);
-			if (page == UFFS_INVALID_PAGE) {
-				uffs_BlockInfoExpire(dev, newBc, i);
-				succRecover = U_TRUE;
-				break;  //end of last page, normal break
-			}
-			page = uffs_FindBestPageInBlock(dev, bc, page);
-			
-			oldTag = GET_TAG(bc, page);
-			buf = uffs_BufClone(dev, NULL);
-			if (buf == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "Can't clone a new buf!");
-				break;
-			}
-			x = uffs_BufLoadPhyData(dev, buf, bc->block, page);
-			if (x == U_FAIL) {
-				if (HAVE_BADBLOCK(dev) && dev->bad.block == bc->block) {
-					// the old block is a bad block, we'll process it later.
-					uffs_Perror(UFFS_ERR_SERIOUS, "the old block %d is a bad block, but ignore it for now.", bc->block);
-				}
-				else {
-					uffs_Perror(UFFS_ERR_SERIOUS, "I/O error ?");
-					uffs_BufFreeClone(dev, buf);
-					flash_op_err = UFFS_FLASH_IO_ERR;
-					break;
-				}
-			}
-			buf->data_len = TAG_DATA_LEN(oldTag);
-			if (buf->data_len > dev->com.pg_data_size) {
-				uffs_Perror(UFFS_ERR_NOISY, "data length over flow!!!");
-				buf->data_len = dev->com.pg_data_size;
-			}
-
-			buf->type = type;
-			buf->parent = parent;
-			buf->serial = serial;
-			buf->data_len = TAG_DATA_LEN(oldTag);
-			buf->page_id = TAG_PAGE_ID(oldTag); 
-
-			TAG_DATA_LEN(tag) = buf->data_len;
-			if (i == 0)
-				data_sum = _GetDirOrFileNameSum(dev, buf);
-
-			flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
-			uffs_BufFreeClone(dev, buf);
-			if (flash_op_err == UFFS_FLASH_BAD_BLK) {
-				uffs_Perror(UFFS_ERR_NORMAL, "new bad block %d discovered.", newBlock);
-				break;
-			}
-			else if (flash_op_err == UFFS_FLASH_IO_ERR) {
-				uffs_Perror(UFFS_ERR_NORMAL, "I/O error ?", newBlock);
-				break;
-			}
-		}
-	} //end of for
-
-	if (i == dev->attr->pages_per_block)
-		succRecover = U_TRUE;
-
-	if (flash_op_err == UFFS_FLASH_BAD_BLK) {
-		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
-		uffs_BlockInfoPut(dev, newBc);
-		if (newNode->u.list.block == dev->bad.block) {
-			// the recovered block is a BAD block, we need to 
-			// deal with it immediately (mark it as 'bad' and put into bad block list).
-			uffs_BadBlockProcess(dev, newNode);
-		}
-		goto retry; // retry on a new erased block ...
-	}
-
-	if (succRecover == U_TRUE) {
-		// now it's time to clean the dirty buffers
-		for (i = 0; i < dev->attr->pages_per_block; i++) {
-			buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
-			if (buf) {
-				if (_BreakFromDirty(dev, buf) == U_SUCC) {
-					buf->mark = UFFS_BUF_VALID;
-					buf->ext_mark &= ~UFFS_BUF_EXT_MARK_TRUNC_TAIL;
-					_MoveNodeToHead(dev, buf);
-				}
-			}
-		}
-
-		// swap the old block node and new block node.
-		// it's important that we 'swap' the block and keep the node unchanged
-		// so that allowing someone hold the node pointer unawared.
-		switch (type) {
-		case UFFS_TYPE_DIR:
-			node->u.dir.parent = parent;
-			node->u.dir.serial = serial;
-			node->u.dir.block = newBlock;
-			node->u.dir.checksum = data_sum;
-			break;
-		case UFFS_TYPE_FILE:
-			node->u.file.parent = parent;
-			node->u.file.serial = serial;
-			node->u.file.block = newBlock;
-			node->u.file.checksum = data_sum;
-			break;
-		case UFFS_TYPE_DATA:
-			node->u.data.parent = parent;
-			node->u.data.serial = serial;
-			node->u.data.block = newBlock;
-			break;
-		default:
-			uffs_Perror(UFFS_ERR_SERIOUS, "UNKNOW TYPE");
-			break;
-		}
-
-		newNode->u.list.block = bc->block;
-		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-
-		// if the recovered block is a bad block, it's time to process it.
-		if (HAVE_BADBLOCK(dev) && dev->bad.block == newNode->u.list.block) {
-			uffs_BadBlockProcess(dev, newNode);
-		}
-		else {
-			// erase recovered block, put it back to erased block list.
-			uffs_FlashEraseBlock(dev, bc->block);
-			if (HAVE_BADBLOCK(dev))
-				uffs_BadBlockProcess(dev, newNode);
-			else
-				uffs_TreeInsertToErasedListTail(dev, newNode);
-		}
-	}
-	else {
-		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
-		uffs_FlashEraseBlock(dev, newBlock);
-		newNode->u.list.block = newBlock;
-		if (HAVE_BADBLOCK(dev))
-			uffs_BadBlockProcess(dev, newNode);
-		else
-			uffs_TreeInsertToErasedListTail(dev, newNode);
-	}
-
-	if (dev->buf.dirtyGroup[slot].dirty != NULL || dev->buf.dirtyGroup[slot].count != 0) {
-		uffs_Perror(UFFS_ERR_NORMAL, "still has dirty buffer ?");
-	}
-
-	uffs_BlockInfoPut(dev, newBc);
-ext:
-	uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-	return (succRecover == U_TRUE ? U_SUCC : U_FAIL);
-
-}
-
-
-
-/** 
- * \brief flush buffer to a new block which is not registered in tree
- *
- * Scenario:
- *		1. get a new block
- *		2. write pages in dirty list to new block, sorted by page_id
- *		3. insert new block to tree
- */
-static URET _BufFlush_NewBlock(uffs_Device *dev, int slot)
-{
-	u8 type;
-	TreeNode *node;
-	uffs_BlockInfo *bc;
-	URET ret;
-
-	ret = U_FAIL;
-
-	node = uffs_TreeGetErasedNode(dev);
-	if (node == NULL) {
-		uffs_Perror(UFFS_ERR_NOISY, "no erased block!");
-		goto ext;
-	}
-	bc = uffs_BlockInfoGet(dev, node->u.list.block);
-	if (bc == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail!");
-		uffs_InsertToErasedListHead(dev, node); //put node back to erased list
-		goto ext;
-	}
-
-	type = dev->buf.dirtyGroup[slot].dirty->type;
-	
-	ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
-
-	if (ret == U_SUCC)
-		uffs_InsertNodeToTree(dev, type, node);
-	else {
-		uffs_FlashEraseBlock(dev, bc->block);
-		uffs_InsertToErasedListHead(dev, node);
-	}		
-
-	uffs_BlockInfoPut(dev, bc);
-ext:
-	return ret;
-}
-
-
-/** 
- * \brief flush buffer to a block with enough free pages 
- *  
- *  pages in dirty list must be sorted by page_id to write to flash
- */
-static
-URET
- uffs_BufFlush_Exist_With_Enough_FreePage(
-		uffs_Device *dev,
-		int slot,			//!< dirty group slot
-		TreeNode *node,		//!< tree node
-		uffs_BlockInfo *bc, //!< block info (Source, also destination)
-		u16 freePages		//!< how many free pages left on destination block
-		)		
-{
-	u16 page;
-	uffs_Buf *buf;
-	uffs_Tags *tag;
-	URET ret;
-	int x;
-
-//	uffs_Perror(UFFS_ERR_NOISY, "Flush buffers with Enough Free Page, in block %d",
-//							bc->block);
-	ret = U_FAIL;
-	for (page = dev->attr->pages_per_block - freePages;	//page: free page num
-			dev->buf.dirtyGroup[slot].count > 0;		//still has dirty pages?
-			page++) {
-
-		buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirtyGroup[slot].dirty);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "count > 0, but no dirty pages in list ?");
-			goto ext;
-		}
-
-		//writre the dirty page (id: buf->page_id) to page i (free page)
-		uffs_BlockInfoLoad(dev, bc, page);
-		tag = GET_TAG(bc, page);
-		TAG_BLOCK_TS(tag) = uffs_GetBlockTimeStamp(dev, bc);
-		TAG_DATA_LEN(tag) = buf->data_len;
-		TAG_TYPE(tag) = buf->type;
-		//tag->data_sum = _GetDirOrFileNameSum(dev, buf);
-		TAG_PARENT(tag) = buf->parent;
-		TAG_SERIAL(tag) = buf->serial;
-		TAG_PAGE_ID(tag) = (u8)(buf->page_id);
-
-		x = uffs_FlashWritePageCombine(dev, bc->block, page, buf, tag);
-		if (x == UFFS_FLASH_IO_ERR) {
-			uffs_Perror(UFFS_ERR_NORMAL, "I/O error <1>?");
-			goto ext;
-		}
-		else if (x == UFFS_FLASH_BAD_BLK) {
-			ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
-			goto ext;
-		}
-		else {
-			if(_BreakFromDirty(dev, buf) == U_SUCC) {
-				buf->mark = UFFS_BUF_VALID;
-				_MoveNodeToHead(dev, buf);
-			}
-		}
-	} //end of for
-	
-	if (dev->buf.dirtyGroup[slot].dirty != NULL || dev->buf.dirtyGroup[slot].count != 0) {
-		uffs_Perror(UFFS_ERR_NORMAL, "still has dirty buffer ?");
-	}
-	else {
-		ret = U_SUCC;
-	}
-
-ext:
-	return ret;
-}
-
-
-URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot)
-{
-	uffs_Buf *dirty;
-	TreeNode *node;
-	uffs_BlockInfo *bc;
-	u16 n;
-	URET ret;
-	u8 type;
-	u16 parent;
-	u16 serial;
-	int block;
-	
-	if (dev->buf.dirtyGroup[slot].count == 0) {
-		return U_SUCC;
-	}
-
-	dirty = dev->buf.dirtyGroup[slot].dirty;
-
-	if (_CheckDirtyList(dirty) == U_FAIL)
-		return U_FAIL;
-
-	type = dirty->type;
-	parent = dirty->parent;
-	serial = dirty->serial;
-
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		node = uffs_TreeFindDirNode(dev, serial);
-		break;
-	case UFFS_TYPE_FILE:
-		node = uffs_TreeFindFileNode(dev, serial);
-		break;
-	case UFFS_TYPE_DATA:
-		node = uffs_TreeFindDataNode(dev, parent, serial);
-		break;
-	default:
-		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type");
-		return U_FAIL;
-	}
-
-	if (node == NULL) {
-		//not found in the tree, need to generate a new block
-		ret = _BufFlush_NewBlock(dev, slot);
-	}
-	else {
-		switch (type) {
-		case UFFS_TYPE_DIR:
-			block = node->u.dir.block;
-			break;
-		case UFFS_TYPE_FILE:
-			block = node->u.file.block;
-			break;
-		case UFFS_TYPE_DATA:
-			block = node->u.data.block;
-			break;
-		default:
-			uffs_Perror(UFFS_ERR_SERIOUS, "unknown type.");
-			return U_FAIL;
-		}
-		bc = uffs_BlockInfoGet(dev, block);
-		if(bc == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail.");
-			return U_FAIL;
-		}
-		uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
-		n = uffs_GetFreePagesCount(dev, bc);
-
-		if (n >= dev->buf.dirtyGroup[slot].count && !force_block_recover) {
-			//The free pages are enough for the dirty pages
-			ret = uffs_BufFlush_Exist_With_Enough_FreePage(dev, slot, node, bc, n);
-		}
-		else {
-			ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
-		}
-		uffs_BlockInfoPut(dev, bc);
-	}
-
-	return ret;
-}
-
-static int _FindMostDirtyGroup(struct uffs_DeviceSt *dev)
-{
-	int i, slot = -1;
-	int max_count = 0;
-
-	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
-		if (dev->buf.dirtyGroup[i].dirty && dev->buf.dirtyGroup[i].lock == 0) {
-			if (dev->buf.dirtyGroup[i].count > max_count) {
-				max_count = dev->buf.dirtyGroup[i].count;
-				slot = i;
-			}
-		}
-	}
-
-	return slot;
-}
-
-/** lock dirty group */
-URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot)
-{
-	URET ret = U_FAIL;
-	if (slot >= 0 && slot < MAX_DIRTY_BUF_GROUPS) {
-		dev->buf.dirtyGroup[slot].lock++;
-		ret = U_SUCC;
-	}	
-	return ret;
-}
-
-/** unlock dirty group */
-URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot)
-{
-	URET ret = U_FAIL;
-
-	if (slot >= 0 && slot < MAX_DIRTY_BUF_GROUPS) {
-		if (dev->buf.dirtyGroup[slot].lock > 0)
-			dev->buf.dirtyGroup[slot].lock--;
-		else {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Try to unlock an unlocked group ?");
-		}
-		ret = U_SUCC;
-	}	
-	return ret;
-}
-
-
-/** 
- * flush buffers to flash.
- * this will flush all dirty groups.
- * \param[in] dev uffs device
- */
-URET uffs_BufFlush(struct uffs_DeviceSt *dev)
-{
-	int slot;
-
-	slot = uffs_BufFindFreeGroupSlot(dev);
-	if (slot >= 0)
-		return U_SUCC;	// do nothing if there is free slot
-	else
-		return uffs_BufFlushMostDirtyGroup(dev);
-}
-
-/** 
- * flush most dirty group
- * \param[in] dev uffs device
- */
-URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev)
-{
-	int slot;
-
-	slot = _FindMostDirtyGroup(dev);
-	if (slot >= 0) {
-		return _BufFlush(dev, U_FALSE, slot);
-	}
-	return U_SUCC;
-}
-
-/** 
- * flush buffers to flash
- * this will pick up a most dirty group, and flush it if there is no free dirty group slot.
- * \param[in] dev uffs device
- * \param[in] force_block_recover #U_TRUE: force a block recover even there are enough free pages
- */
-URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
-{
-	int slot;
-
-	slot = uffs_BufFindFreeGroupSlot(dev);
-	if (slot >= 0) {
-		return U_SUCC;  //there is free slot, do nothing.
-	}
-	else {
-		slot = _FindMostDirtyGroup(dev);
-		return _BufFlush(dev, force_block_recover, slot);
-	}
-}
-
-/**
- * flush buffer group with given parent/serial num.
- *
- * \param[in] dev uffs device
- * \param[in] parent parent num of the group
- * \param[in] serial serial num of the group
- */
-URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
-{
-	int slot;
-
-	slot = uffs_BufFindGroupSlot(dev, parent, serial);
-	if (slot >= 0) {
-		return _BufFlush(dev, U_FALSE, slot);
-	}
-
-	return U_SUCC;
-}
-
-/**
- * flush buffer group with given parent/serial num and force_block_recover indicator.
- *
- * \param[in] dev uffs device
- * \param[in] parent parent num of the group
- * \param[in] serial serial num of group
- * \param[in] force_block_recover indicator
- */
-URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev, u16 parent, u16 serial, UBOOL force_block_recover)
-{
-	int slot;
-
-	slot = uffs_BufFindGroupSlot(dev, parent, serial);
-	if (slot >= 0) {
-		return _BufFlush(dev, force_block_recover, slot);
-	}
-
-	return U_SUCC;
-}
-
-
-/**
- * flush buffer group/groups which match given parent num.
- *
- * \param[in] dev uffs device
- * \param[in] parent parent num of the group
- * \param[in] serial serial num of group
- * \param[in] force_block_recover indicator
- */
-URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent)
-{
-	int slot;
-	uffs_Buf *buf;
-	URET ret = U_SUCC;
-
-	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS && ret == U_SUCC; slot++) {
-		if (dev->buf.dirtyGroup[slot].dirty) {
-			buf = dev->buf.dirtyGroup[slot].dirty;
-			if (buf->parent == parent) {
-				ret = _BufFlush(dev, U_FALSE, slot);
-			}
-		}
-	}
-
-	return ret;
-}
-
-/**
- * find a free dirty group slot
- *
- * \param[in] dev uffs device
- * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one, otherwise return -1.
- */
-int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev)
-{
-	int i, slot = -1;
-
-	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
-		if (dev->buf.dirtyGroup[i].dirty == NULL) {
-			slot = i;
-			break;
-		}
-	}
-	return slot;
-}
-
-/**
- * find a dirty group slot with given parent/serial num.
- *
- * \param[in] dev uffs device
- * \param[in] parent parent num of the group
- * \param[in] serial serial num of group
- * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one, otherwise return -1.
- */
-int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
-{
-	uffs_Buf *buf;
-	int i, slot = -1;
-
-	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
-		if (dev->buf.dirtyGroup[i].dirty) {
-			buf = dev->buf.dirtyGroup[i].dirty;
-			if (buf->parent == parent && buf->serial == serial) {
-				slot = i;
-				break;
-			}
-		}
-	}
-	return slot;
-}
-
-/** 
- * \brief get a page buffer
- * \param[in] dev uffs device
- * \param[in] parent parent serial num
- * \param[in] serial serial num
- * \param[in] page_id page_id
- * \return return the buffer found in buffer list, if not found, return NULL.
- */
-uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 parent, u16 serial, u16 page_id)
-{
-	uffs_Buf *p;
-
-	//first, check whether the buffer exist in buf list ?
-	p = uffs_BufFind(dev, parent, serial, page_id);
-
-	if (p) {
-		p->ref_count++;
-		_MoveNodeToHead(dev, p);
-	}
-
-	return p;
-}
-
-/** 
- * New generate a buffer
- */
-uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 parent, u16 serial, u16 page_id)
-{
-	uffs_Buf *buf;
-
-	buf = uffs_BufGet(dev, parent, serial, page_id);
-	if (buf) {
-		if (buf->ref_count > 1) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "When create new buf, an exist buffer has ref count %d, possibly bug!", buf->ref_count);
-		}
-		else {
-			buf->data_len = 0;
-		}
-		_MoveNodeToHead(dev, buf);
-		return buf;
-	}
-
-	buf = _FindFreeBuf(dev);
-	if (buf == NULL) {
-		uffs_BufFlushMostDirtyGroup(dev);
-		buf = _FindFreeBuf(dev);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "no free page buf!");
-			return NULL;
-		}
-	}
-
-	buf->mark = UFFS_BUF_EMPTY;
-	buf->type = type;
-	buf->parent = parent;
-	buf->serial = serial;
-	buf->page_id = page_id;
-	buf->data_len = 0;
-	buf->ref_count++;
-	memset(buf->data, 0xff, dev->com.pg_data_size);
-
-	_MoveNodeToHead(dev, buf);
-	
-	return buf;	
-}
-
-
-
-/** 
- * get a page buffer
- * \param[in] dev uffs device
- * \param[in] type dir, file or data ?
- * \param[in] node node on the tree
- * \param[in] page_id page_id
- * \return return the buffer if found in buffer list, if not found in 
- *			buffer list, it will get a free buffer, and load data from flash.
- *			return NULL if not free buffer.
- */
-uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 page_id)
-{
-	uffs_Buf *buf;
-	u16 parent, serial, block, page;
-	uffs_BlockInfo *bc;
-
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		parent = node->u.dir.parent;
-		serial = node->u.dir.serial;
-		block = node->u.dir.block;
-		break;
-	case UFFS_TYPE_FILE:
-		parent = node->u.file.parent;
-		serial = node->u.file.serial;
-		block = node->u.file.block;
-		break;
-	case UFFS_TYPE_DATA:
-		parent = node->u.data.parent;
-		serial = node->u.data.serial;
-		block = node->u.data.block;
-		break;
-	default:
-		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type");
-		return NULL;
-	}
-
-	buf = uffs_BufFind(dev, parent, serial, page_id);
-	if (buf) {
-		buf->ref_count++;
-		return buf;
-	}
-
-	buf = _FindFreeBuf(dev);
-	if (buf == NULL) {
-		uffs_BufFlushMostDirtyGroup(dev);
-		buf = _FindFreeBuf(dev);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "no free page buf!");
-			return NULL;
-		}
-	}
-
-	bc = uffs_BlockInfoGet(dev, block);
-	if (bc == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Can't get block info!");
-		return NULL;
-	}
-	
-	page = uffs_FindPageInBlockWithPageId(dev, bc, page_id);
-	if (page == UFFS_INVALID_PAGE) {
-		uffs_BlockInfoPut(dev, bc);
-		uffs_Perror(UFFS_ERR_SERIOUS, "can't find right page ?");
-		return NULL;
-	}
-	page = uffs_FindBestPageInBlock(dev, bc, page);
-	uffs_BlockInfoPut(dev, bc);
-
-	buf->mark = UFFS_BUF_EMPTY;
-	buf->type = type;
-	buf->parent = parent;
-	buf->serial = serial;
-	buf->page_id = page_id;
-
-	if (UFFS_FLASH_HAVE_ERR(uffs_FlashReadPage(dev, block, page, buf))) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "can't load page from flash !");
-		return NULL;
-	}
-
-	buf->data_len = TAG_DATA_LEN(GET_TAG(bc, page));
-	buf->mark = UFFS_BUF_VALID;
-	buf->ref_count++;
-
-	_MoveNodeToHead(dev, buf);
-	
-	return buf;
-
-}
-
-/** 
- * \brief Put back a page buffer, make reference count decrease by one
- * \param[in] dev uffs device
- * \param[in] buf buffer to be put back
- */
-URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
-{
-	URET ret = U_FAIL;
-
-	dev = dev;
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_NORMAL,  "Can't put an NULL buffer!");
-	}
-	else if (buf->ref_count == 0) {
-		uffs_Perror(UFFS_ERR_NORMAL,  "Putting an unused page buffer ? ");
-	}
-	else if (buf->ref_count == CLONE_BUF_MARK) {
-		uffs_Perror(UFFS_ERR_NORMAL, "Putting an cloned page buffer ? ");
-		ret = uffs_BufFreeClone(dev, buf);
-	}
-	else {
-		buf->ref_count--;
-		ret = U_SUCC;
-	}
-
-	return ret;
-}
-
-
-/** 
- * \brief clone from an exist buffer.
-		allocate memory for new buffer, and copy data from original buffer if 
-		original buffer is not NULL. 
- * \param[in] dev uffs device
- * \param[in] buf page buffer to be clone from. if NULL presented here, data copy will not be processed
- * \return return the cloned page buffer, all data copied from source
- * \note the cloned buffer is not linked in page buffer list in uffs device,
- *			so you should use #uffs_BufFreeClone instead of #uffs_BufPut when you put back or release buffer
- */
-uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
-{
-	uffs_Buf *p;
-
-	p = _FindFreeBufEx(dev, 1);
-	if (p == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "no enough free pages for clone! Please increase Clone Buffer Count threshold.");
-	}
-	else {
-		_BreakFromBufList(dev, p);
-
-		if (buf) {
-			p->parent = buf->parent;
-			p->type = buf->type;
-			p->serial = buf->serial;
-			p->page_id = buf->page_id;
-			
-			p->data_len = buf->data_len;
-			//athough the valid data length is .data_len,
-			//but we still need copy the whole buffer, include header
-			memcpy(p->header, buf->header, dev->com.pg_size);
-		}
-		p->next = p->prev = NULL;			//because the cloned one is not linked to device buffer
-		p->next_dirty = p->prev_dirty = NULL;
-		p->ref_count = CLONE_BUF_MARK;		//CLONE_BUF_MARK indicates that this is an cloned buffer
-	}
-
-	return p;
-}
-
-/** 
- * \brief release cloned buffer
- * \param[in] dev uffs device
- * \param[in] buf cloned buffer
- */
-URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
-{
-	dev = dev; //make compiler happy
-	if (!buf)
-		return U_FAIL;
-
-	if (buf->ref_count != CLONE_BUF_MARK) {
-		/* a cloned buffer must have a ref_count of CLONE_BUF_MARK */
-		uffs_Perror(UFFS_ERR_SERIOUS,  "Try to release a non-cloned page buffer ?");
-		return U_FAIL;
-	}
-
-	buf->ref_count = 0;
-	buf->mark = UFFS_BUF_EMPTY;
-	_LinkToBufListTail(dev, buf);
-
-	return U_SUCC;
-}
-
-
-
-UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
-{
-	uffs_Buf *buf = dev->buf.head;
-
-	while (buf) {
-		if(buf->ref_count != 0) return U_FALSE;
-		buf = buf->next;
-	}
-
-	return U_TRUE;
-}
-
-UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
-{
-	uffs_Buf *buf = dev->buf.head;
-
-	while (buf) {
-		if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
-		buf = buf->next;
-	}
-
-	return U_TRUE;
-}
-
-
-URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
-{
-	uffs_Buf *buf = dev->buf.head;
-
-	while (buf) {
-		buf->mark = UFFS_BUF_EMPTY;
-		buf = buf->next;
-	}
-	return U_SUCC;
-}
-
-
-void uffs_BufIncRef(uffs_Buf *buf)
-{
-	buf->ref_count++;
-}
-
-void uffs_BufDecRef(uffs_Buf *buf)
-{
-	if (buf->ref_count > 0)
-		buf->ref_count--;
-}
-
-/** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0, and discard all data it holds */
-void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf)
-{
-	if (buf->mark != UFFS_BUF_EMPTY) {
-		if (buf->ref_count == 0) {
-			if (buf->mark == UFFS_BUF_DIRTY)
-				_BreakFromDirty(dev, buf);
-			buf->mark = UFFS_BUF_EMPTY;
-		}
-	}
-}
-
-#if 0
-static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
-{
-	uffs_Buf *p = dev->buf.dirtyGroup[slot].dirty;
-
-	while (p) {
-		if(p == buf) return U_TRUE;
-		p = p->next_dirty;
-	}
-
-	return U_FALSE;
-}
-#endif
-
-URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
-{
-	int slot;
-
-	if(ofs + len > dev->com.pg_data_size) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "data length out of range! %d+%d", ofs, len);
-		return U_FAIL;
-	}
-
-	slot = uffs_BufFindGroupSlot(dev, buf->parent, buf->serial);
-
-	if (slot < 0) {
-		// need to take a free slot
-		slot = uffs_BufFindFreeGroupSlot(dev);
-		if (slot < 0) {
-			// no free slot ? flush buffer
-			if (uffs_BufFlushMostDirtyGroup(dev) != U_SUCC)
-				return U_FAIL;
-
-			slot = uffs_BufFindFreeGroupSlot(dev);
-			if (slot < 0) {
-				// still no free slot ??
-				uffs_Perror(UFFS_ERR_SERIOUS, "no free slot ?");
-				return U_FAIL;
-			}
-		}
-	}
-
-	memcpy(buf->data + ofs, data, len);
-
-	if (ofs + len > buf->data_len) 
-		buf->data_len = ofs + len;
-	
-	if (_IsBufInInDirtyList(dev, slot, buf) == U_FALSE) {
-		_LinkToDirtyList(dev, slot, buf);
-	}
-
-	if (dev->buf.dirtyGroup[slot].count >= dev->buf.dirty_buf_max) {
-		if (uffs_BufFlushGroup(dev, buf->parent, buf->serial) != U_SUCC) {
-			return U_FAIL;
-		}
-	}
-
-	return U_SUCC;
-}
-
-URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
-{
-	u32 readSize;
-	u32 pg_data_size = dev->com.pg_data_size;
-
-	readSize = (ofs >= pg_data_size ? 0 : (ofs + len >= pg_data_size ? pg_data_size - ofs : len));
-
-	if (readSize > 0) 
-		memcpy(data, buf->data + ofs, readSize);
-
-	return U_SUCC;
-}
-
-
-
-
-
-
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+/** 
+ * \file uffs_buf.c
+ * \brief uffs page buffers manipulations
+ * \author Ricky Zheng
+ * \note Created in 11th May, 2005
+ */
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_buf.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_pool.h"
+#include "uffs/uffs_ecc.h"
+#include "uffs/uffs_badblock.h"
+#include <string.h>
+
+#define PFX "pbuf: "
+
+
+URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot);
+
+
+/**
+ * \brief inspect (print) uffs page buffers.
+ * \param[in] dev uffs device to be inspected.
+ */
+void uffs_BufInspect(uffs_Device *dev)
+{
+	struct uffs_PageBufDescSt *pb = &dev->buf;
+	uffs_Buf *buf;
+
+	uffs_PerrorRaw(UFFS_ERR_NORMAL, "------------- page buffer inspect ---------" TENDSTR);
+	uffs_PerrorRaw(UFFS_ERR_NORMAL, "all buffers: " TENDSTR);
+	for (buf = pb->head; buf; buf = buf->next) {
+		if (buf->mark != 0) {
+			uffs_PerrorRaw(UFFS_ERR_NORMAL, "\tF:%04x S:%04x P:%02d R:%02d D:%03d M:%c EM:%d"  TENDSTR, 
+				buf->parent, buf->serial, buf->page_id, buf->ref_count, buf->data_len, buf->mark == UFFS_BUF_VALID ? 'V' : 'D', buf->ext_mark);
+		}
+	}
+	uffs_PerrorRaw(UFFS_ERR_NORMAL, "--------------------------------------------"  TENDSTR);
+}
+
+/**
+ * \brief initialize page buffers for device
+ * in UFFS, each device has one buffer pool
+ * \param[in] dev uffs device
+ * \param[in] buf_max maximum buffer number, normally use #MAX_PAGE_BUFFERS
+ * \param[in] dirty_buf_max maximum dirty buffer allowed, if the dirty buffer over this number,
+ *            than need to be flush to flash
+ */
+URET uffs_BufInit(uffs_Device *dev, int buf_max, int dirty_buf_max)
+{
+	void *pool;
+	u8 *data;
+	uffs_Buf *buf;
+	int size;
+	int i, slot;
+
+	if (!dev)
+		return U_FAIL;
+
+	//init device common parameters, which are needed by page buffers
+	dev->com.pg_size = dev->attr->page_data_size;  // we use the whole page.
+	dev->com.header_size = sizeof(struct uffs_MiniHeaderSt);	// mini header
+	dev->com.pg_data_size = dev->com.pg_size - dev->com.header_size;
+
+	if (dev->buf.pool != NULL) {
+		uffs_Perror(UFFS_ERR_NORMAL, "buf.pool is not NULL, buf already inited ?");
+		return U_FAIL;
+	}
+	
+	size = (sizeof(uffs_Buf) + dev->com.pg_size) * buf_max;
+	if (dev->mem.pagebuf_pool_size == 0) {
+		if (dev->mem.malloc) {
+			dev->mem.pagebuf_pool_buf = dev->mem.malloc(dev, size);
+			if (dev->mem.pagebuf_pool_buf)
+				dev->mem.pagebuf_pool_size = size;
+		}
+	}
+	if (size > dev->mem.pagebuf_pool_size) {
+		uffs_Perror(UFFS_ERR_DEAD, "page buffers require %d but only %d available.", size, dev->mem.pagebuf_pool_size);
+		return U_FAIL;
+	}
+	pool = dev->mem.pagebuf_pool_buf;
+
+	uffs_Perror(UFFS_ERR_NOISY, "alloc %d bytes.", size);
+	dev->buf.pool = pool;
+
+	for (i = 0; i < buf_max; i++) {
+		buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
+		memset(buf, 0, sizeof(uffs_Buf));
+		data = (u8 *)pool + (sizeof(uffs_Buf) * buf_max) + (dev->com.pg_size * i);
+		buf->header = data;
+		buf->data = data + dev->com.header_size;
+		buf->mark = UFFS_BUF_EMPTY;
+		memset(buf->header, 0, dev->com.pg_size);
+		if (i == 0) {
+			buf->prev = NULL;
+			dev->buf.head = buf;
+		}
+		else {
+			buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
+		}
+
+		if (i == (buf_max - 1)) {
+			buf->next = NULL;
+			dev->buf.tail = buf;
+		}
+		else {
+			buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
+		}
+	}
+
+	dev->buf.buf_max = buf_max;
+	dev->buf.dirty_buf_max = (dirty_buf_max > dev->attr->pages_per_block ? dev->attr->pages_per_block : dirty_buf_max);
+
+	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
+		dev->buf.dirtyGroup[slot].dirty = NULL;
+		dev->buf.dirtyGroup[slot].count = 0;
+	}
+	return U_SUCC;
+}
+
+/**
+ * \brief flush all buffers
+ */
+URET uffs_BufFlushAll(struct uffs_DeviceSt *dev)
+{
+	int slot;
+	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
+		if(_BufFlush(dev, FALSE, slot) != U_SUCC) {
+			uffs_Perror(UFFS_ERR_NORMAL, "fail to flush buffer(slot %d)", slot);
+			return U_FAIL;
+		}
+	}
+	return U_SUCC;
+}
+
+/** 
+ * \brief release all page buffer, this function should be called 
+			when unmounting a uffs device
+ * \param[in] dev uffs device
+ * \note if there are page buffers in used, it may cause fail to release
+ */
+URET uffs_BufReleaseAll(uffs_Device *dev)
+{
+	uffs_Buf *p;
+
+	if (!dev)
+		return U_FAIL;
+
+	//now release all buffer
+	p = dev->buf.head;
+	while (p) {
+		if (p->ref_count != 0) {
+			uffs_Perror(UFFS_ERR_NORMAL, 
+				PFX "can't release buffers, \
+					parent:%d, serial:%d, page_id:%d still in used.\n", p->parent, p->serial, p->page_id);
+			return U_FAIL;
+		}
+		p = p->next;
+	}
+
+	if (uffs_BufFlushAll(dev) != U_SUCC) {
+		uffs_Perror(UFFS_ERR_NORMAL, "can't release buf, fail to flush buffer");
+		return U_FAIL;
+	}
+
+	if (dev->mem.free)
+		dev->mem.free(dev, dev->buf.pool);
+
+	dev->buf.pool = NULL;
+	dev->buf.head = dev->buf.tail = NULL;
+
+	return U_SUCC;
+}
+
+
+static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
+{
+	if(buf->next)
+		buf->next->prev = buf->prev;
+
+	if(buf->prev)
+		buf->prev->next = buf->next;
+
+	if(dev->buf.head == buf)
+		dev->buf.head = buf->next;
+
+	if(dev->buf.tail == buf)
+		dev->buf.tail = buf->prev;
+
+}
+
+static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
+{
+	if (buf == dev->buf.head)
+		return;
+
+	buf->prev = NULL;
+	buf->next = dev->buf.head;
+
+	if (dev->buf.head)
+		dev->buf.head->prev = buf;
+
+	if (dev->buf.tail == NULL)
+		dev->buf.tail = buf;
+
+	dev->buf.head = buf;
+}
+
+static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
+{
+	if (dev->buf.tail == buf)
+		return;
+
+	buf->prev = dev->buf.tail;
+	buf->next = NULL;
+
+	if (dev->buf.tail)
+		dev->buf.tail->next = buf;
+
+	if (dev->buf.head == NULL)
+		dev->buf.head = buf;
+
+	dev->buf.tail = buf;
+}
+
+//move a node which linked in the list to the head of list
+static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
+{
+	if (p == dev->buf.head)
+		return;
+
+	//break from list
+	_BreakFromBufList(dev, p);
+
+	//link to head
+	_LinkToBufListHead(dev, p);
+}
+
+// check if the buf is already in dirty list
+static UBOOL _IsBufInInDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
+{
+	uffs_Buf *work;
+	work = dev->buf.dirtyGroup[slot].dirty;
+	while (work) {
+		if (work == buf) 
+			return U_TRUE;
+		work = work->next_dirty;
+	}
+
+	return U_FALSE;
+}
+
+static void _LinkToDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
+{
+
+	if (buf == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "Try to insert a NULL node into dirty list ?");
+		return;
+	}
+
+	buf->mark = UFFS_BUF_DIRTY;
+	buf->prev_dirty = NULL;
+	buf->next_dirty = dev->buf.dirtyGroup[slot].dirty;
+
+	if (dev->buf.dirtyGroup[slot].dirty) 
+		dev->buf.dirtyGroup[slot].dirty->prev_dirty = buf;
+
+	dev->buf.dirtyGroup[slot].dirty = buf;
+	dev->buf.dirtyGroup[slot].count++;
+}
+
+static int CountFreeBuf(uffs_Device *dev)
+{
+	int count = 0;
+
+	uffs_Buf *buf = dev->buf.head;
+
+	while (buf) {
+
+		if (buf->ref_count == 0 && 
+			buf->mark != UFFS_BUF_DIRTY)
+			count++;
+
+		buf = buf->next;
+	}
+
+	return count;
+}
+
+static uffs_Buf * _FindFreeBufEx(uffs_Device *dev, int clone)
+{
+	uffs_Buf *buf;
+
+	if (!clone && CountFreeBuf(dev) <= CLONE_BUFFERS_THRESHOLD)
+		return NULL;
+
+#if 1
+	buf = dev->buf.head;
+	while (buf) {
+
+		if (buf->ref_count == 0 && 
+			buf->mark != UFFS_BUF_DIRTY)
+			return buf;
+
+		buf = buf->next;
+	}
+#else
+	buf = dev->buf.tail;
+	while (buf) {
+
+		if(buf->ref_count == 0 &&
+			buf->mark != UFFS_BUF_DIRTY) 
+			return buf;
+
+		buf = buf->prev;
+	}
+#endif
+
+	return buf;
+}
+
+static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
+{
+	return _FindFreeBufEx(dev, 0);
+}
+
+
+/** 
+ * load psychical page data into buf and do ecc check 
+ * \param[in] dev uffs device
+ * \param[in] buf buf to be load in
+ * \param[in] block psychical block number
+ * \param[in] page psychical page number
+ * \return return U_SUCC if no error, return U_FAIL if I/O error or ecc check fail
+ */
+URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
+{
+	int ret;
+
+	ret = uffs_FlashReadPage(dev, block, page, buf);
+
+	if (UFFS_FLASH_HAVE_ERR(ret)) {
+		buf->mark = UFFS_BUF_EMPTY;
+		return U_FAIL;
+	}
+	else {
+		buf->mark = UFFS_BUF_VALID;
+		return U_SUCC;
+	}
+}
+
+/** 
+ * \brief load psychical page data into buf and ignore ECC result
+ *
+ * \param[in] dev uffs device
+ * \param[in] buf buf to be load in
+ * \param[in] block psychical block number
+ * \param[in] page psychical page number
+ *
+ * \return return U_SUCC if no error, return U_FAIL if I/O error
+ * \note this function should be only used when doing bad block recover.
+ */
+URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
+{
+	int ret;
+
+	ret = uffs_FlashReadPage(dev, block, page, buf);
+
+	if (ret == UFFS_FLASH_IO_ERR) {
+		buf->mark = UFFS_BUF_EMPTY;
+		return U_FAIL;
+	}
+	else {
+		buf->mark = UFFS_BUF_VALID;
+		return U_SUCC;
+	}
+}
+
+
+/** 
+ * find a buffer in the pool
+ * \param[in] dev uffs device
+ * \param[in] parent parent serial num
+ * \param[in] serial serial num
+ * \param[in] page_id page_id
+ * \return return found buffer, return NULL if buffer not found
+ */
+uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 parent, u16 serial, u16 page_id)
+{
+	uffs_Buf *p = dev->buf.head;
+
+	while (p) {
+		if(	p->parent == parent &&
+			p->serial == serial &&
+			p->page_id == page_id &&
+			p->mark != UFFS_BUF_EMPTY) 
+		{
+			//they have match one
+			return p;
+		}
+		p = p->next;
+	}
+
+	return NULL; //buffer not found
+}
+
+static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 page_id)
+{
+	while(dirty) {
+		if (dirty->page_id == page_id) 
+			return dirty;
+		dirty = dirty->next_dirty;
+	}
+	return NULL;
+}
+
+static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
+{
+	int slot = -1;
+
+	if (dirtyBuf->mark != UFFS_BUF_DIRTY) {
+		uffs_Perror(UFFS_ERR_NORMAL, "try to break a non-dirty buf from dirty list ?");
+		return U_FAIL;
+	}
+
+	slot = uffs_BufFindGroupSlot(dev, dirtyBuf->parent, dirtyBuf->serial);
+	if (slot < 0) {
+		uffs_Perror(UFFS_ERR_NORMAL, "no dirty list exit ?");
+		return U_FAIL;
+	}
+
+	// break from the link
+	if (dirtyBuf->next_dirty) {
+		dirtyBuf->next_dirty->prev_dirty = dirtyBuf->prev_dirty;
+	}
+
+	if (dirtyBuf->prev_dirty) {
+		dirtyBuf->prev_dirty->next_dirty = dirtyBuf->next_dirty;
+	}
+
+	// check if it's the link head ...
+	if (dev->buf.dirtyGroup[slot].dirty == dirtyBuf) {
+		dev->buf.dirtyGroup[slot].dirty = dirtyBuf->next_dirty;
+	}
+
+	dirtyBuf->next_dirty = dirtyBuf->prev_dirty = NULL; // clear dirty link
+
+	dev->buf.dirtyGroup[slot].count--;
+
+	return U_SUCC;
+}
+
+static u16 _GetDirOrFileNameSum(uffs_Device *dev, uffs_Buf *buf)
+{
+	u16 data_sum = 0; //default: 0
+	uffs_FileInfo *fi;
+	
+	dev = dev;
+	//FIXME: We use the same schema for both dir and file.
+	if (buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
+		if (buf->page_id == 0) {
+			fi = (uffs_FileInfo *)(buf->data);
+			data_sum = uffs_MakeSum16(fi->name, fi->name_len);
+		}
+	}
+
+	return data_sum;
+}
+
+
+static URET _CheckDirtyList(uffs_Buf *dirty)
+{
+	u16 parent;
+	u16 serial;
+
+	if (dirty == NULL) {
+		return U_SUCC;
+	}
+
+	parent = dirty->parent;
+	serial = dirty->serial;
+	dirty = dirty->next_dirty;
+
+	while (dirty) {
+		if (parent != dirty->parent ||
+			serial != dirty->serial) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "parent or serial in dirty pages buffer are not the same ?");
+			return U_FAIL;
+		}
+		if (dirty->mark != UFFS_BUF_DIRTY) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "non-dirty page buffer in dirty buffer list ?");
+			return U_FAIL;
+		}
+		dirty = dirty->next_dirty;
+	}
+	return U_SUCC;
+}
+
+/** find a page in dirty list, which has minimum page_id */
+uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
+{
+	uffs_Buf * work = dirtyList;
+	uffs_Buf * buf = dirtyList;
+
+	work = work->next_dirty;
+	while (work) {
+		if (work->page_id < buf->page_id)
+			buf = work;
+		work = work->next_dirty;
+	}
+	return buf;
+}
+
+
+/** 
+ * \brief flush buffer with block recover
+ *
+ * Scenario: 
+ *		1. get a free (erased) block --> newNode <br>
+ *		2. copy from old block ---> oldNode, or copy from dirty list, <br>
+ *			sorted by page_id, to new block. Skips the invalid pages when copy pages.<br>
+ *		3. erased old block. set new info to oldNode, set newNode->block = old block,<br>
+ *			and put newNode to erased list.<br>
+ *	\note IT'S IMPORTANT TO KEEP OLD NODE IN THE LIST, so you don't need to update the obj->node :-)
+ */
+static URET uffs_BufFlush_Exist_With_BlockCover(
+			uffs_Device *dev,
+			int slot,			//!< dirty group slot
+			TreeNode *node,		//!< old data node on tree
+			uffs_BlockInfo *bc	//!< old data block info
+			)
+{
+	u16 i;
+	u8 type, timeStamp;
+	u16 page, parent, serial;
+	uffs_Buf *buf;
+	TreeNode *newNode;
+	uffs_BlockInfo *newBc;
+	uffs_Tags *tag, *oldTag;
+	int x;
+	u16 newBlock;
+	UBOOL succRecover;			//U_TRUE: recover successful, erase old block,
+								//U_FALSE: fail to recover, erase new block
+	UBOOL flash_op_err;
+	u16 data_sum=0;
+
+	type = dev->buf.dirtyGroup[slot].dirty->type;
+	parent = dev->buf.dirtyGroup[slot].dirty->parent;
+	serial = dev->buf.dirtyGroup[slot].dirty->serial;
+
+retry:
+	flash_op_err = UFFS_FLASH_NO_ERR;
+	succRecover = U_FALSE;
+
+	newNode = uffs_TreeGetErasedNode(dev);
+	if (newNode == NULL) {
+		uffs_Perror(UFFS_ERR_NOISY, "no enough erased block!");
+		goto ext;
+	}
+	newBlock = newNode->u.list.block;
+	newBc = uffs_BlockInfoGet(dev, newBlock);
+	if (newBc == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail!");
+		uffs_InsertToErasedListHead(dev, newNode);  //put node back to erased list
+													//because it doesn't use, so put to head
+		goto ext;
+	}
+
+	uffs_BlockInfoLoad(dev, newBc, UFFS_ALL_PAGES);
+	timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));
+
+//	uffs_Perror(UFFS_ERR_NOISY, "Flush buffers with Block Recover, from %d to %d", 
+//					bc->block, newBc->block);
+
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		tag = GET_TAG(newBc, i);
+		TAG_BLOCK_TS(tag) = timeStamp;
+		TAG_PARENT(tag) = parent;
+		TAG_SERIAL(tag) = serial;
+		TAG_TYPE(tag) = type;
+		TAG_PAGE_ID(tag) = (u8)i; //now, page_id = page, FIX ME!! if more than 256 pages in a block
+		
+		buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
+		if (buf != NULL) {
+			if (i == 0)
+				data_sum = _GetDirOrFileNameSum(dev, buf);
+
+			TAG_DATA_LEN(tag) = buf->data_len;
+
+			if (buf->data_len == 0) // this could happen when truncating a file
+				flash_op_err = UFFS_FLASH_NO_ERR;
+			else
+				flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
+
+			if (flash_op_err == UFFS_FLASH_BAD_BLK) {
+				uffs_Perror(UFFS_ERR_NORMAL, "new bad block %d discovered.", newBlock);
+				break;
+			}
+			else if (flash_op_err == UFFS_FLASH_IO_ERR) {
+				uffs_Perror(UFFS_ERR_NORMAL, "writing to block %d page %d, I/O error ?", (int)newBlock, (int)i);
+				break;
+			}
+			else if (buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL) {
+				// when truncating a file, the last dirty buf will be set as UFFS_BUF_EXT_MARK_TAIL.
+				// so that we don't do page recovery for the rest pages in the block.
+				uffs_BlockInfoExpire(dev, newBc, i);
+				succRecover = U_TRUE;
+				break;
+			}
+		}
+		else {
+			page = uffs_FindPageInBlockWithPageId(dev, bc, i);
+			if (page == UFFS_INVALID_PAGE) {
+				uffs_BlockInfoExpire(dev, newBc, i);
+				succRecover = U_TRUE;
+				break;  //end of last page, normal break
+			}
+			page = uffs_FindBestPageInBlock(dev, bc, page);
+			
+			oldTag = GET_TAG(bc, page);
+			buf = uffs_BufClone(dev, NULL);
+			if (buf == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "Can't clone a new buf!");
+				break;
+			}
+			x = uffs_BufLoadPhyData(dev, buf, bc->block, page);
+			if (x == U_FAIL) {
+				if (HAVE_BADBLOCK(dev) && dev->bad.block == bc->block) {
+					// the old block is a bad block, we'll process it later.
+					uffs_Perror(UFFS_ERR_SERIOUS, "the old block %d is a bad block, but ignore it for now.", bc->block);
+				}
+				else {
+					uffs_Perror(UFFS_ERR_SERIOUS, "I/O error ?");
+					uffs_BufFreeClone(dev, buf);
+					flash_op_err = UFFS_FLASH_IO_ERR;
+					break;
+				}
+			}
+			buf->data_len = TAG_DATA_LEN(oldTag);
+			if (buf->data_len > dev->com.pg_data_size) {
+				uffs_Perror(UFFS_ERR_NOISY, "data length over flow!!!");
+				buf->data_len = dev->com.pg_data_size;
+			}
+
+			buf->type = type;
+			buf->parent = parent;
+			buf->serial = serial;
+			buf->data_len = TAG_DATA_LEN(oldTag);
+			buf->page_id = TAG_PAGE_ID(oldTag); 
+
+			TAG_DATA_LEN(tag) = buf->data_len;
+			if (i == 0)
+				data_sum = _GetDirOrFileNameSum(dev, buf);
+
+			flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
+			uffs_BufFreeClone(dev, buf);
+			if (flash_op_err == UFFS_FLASH_BAD_BLK) {
+				uffs_Perror(UFFS_ERR_NORMAL, "new bad block %d discovered.", newBlock);
+				break;
+			}
+			else if (flash_op_err == UFFS_FLASH_IO_ERR) {
+				uffs_Perror(UFFS_ERR_NORMAL, "I/O error ?", newBlock);
+				break;
+			}
+		}
+	} //end of for
+
+	if (i == dev->attr->pages_per_block)
+		succRecover = U_TRUE;
+
+	if (flash_op_err == UFFS_FLASH_BAD_BLK) {
+		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
+		uffs_BlockInfoPut(dev, newBc);
+		if (newNode->u.list.block == dev->bad.block) {
+			// the recovered block is a BAD block, we need to 
+			// deal with it immediately (mark it as 'bad' and put into bad block list).
+			uffs_BadBlockProcess(dev, newNode);
+		}
+		goto retry; // retry on a new erased block ...
+	}
+
+	if (succRecover == U_TRUE) {
+		// now it's time to clean the dirty buffers
+		for (i = 0; i < dev->attr->pages_per_block; i++) {
+			buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
+			if (buf) {
+				if (_BreakFromDirty(dev, buf) == U_SUCC) {
+					buf->mark = UFFS_BUF_VALID;
+					buf->ext_mark &= ~UFFS_BUF_EXT_MARK_TRUNC_TAIL;
+					_MoveNodeToHead(dev, buf);
+				}
+			}
+		}
+
+		// swap the old block node and new block node.
+		// it's important that we 'swap' the block and keep the node unchanged
+		// so that allowing someone hold the node pointer unawared.
+		switch (type) {
+		case UFFS_TYPE_DIR:
+			node->u.dir.parent = parent;
+			node->u.dir.serial = serial;
+			node->u.dir.block = newBlock;
+			node->u.dir.checksum = data_sum;
+			break;
+		case UFFS_TYPE_FILE:
+			node->u.file.parent = parent;
+			node->u.file.serial = serial;
+			node->u.file.block = newBlock;
+			node->u.file.checksum = data_sum;
+			break;
+		case UFFS_TYPE_DATA:
+			node->u.data.parent = parent;
+			node->u.data.serial = serial;
+			node->u.data.block = newBlock;
+			break;
+		default:
+			uffs_Perror(UFFS_ERR_SERIOUS, "UNKNOW TYPE");
+			break;
+		}
+
+		newNode->u.list.block = bc->block;
+		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+
+		// if the recovered block is a bad block, it's time to process it.
+		if (HAVE_BADBLOCK(dev) && dev->bad.block == newNode->u.list.block) {
+			uffs_BadBlockProcess(dev, newNode);
+		}
+		else {
+			// erase recovered block, put it back to erased block list.
+			uffs_FlashEraseBlock(dev, bc->block);
+			if (HAVE_BADBLOCK(dev))
+				uffs_BadBlockProcess(dev, newNode);
+			else
+				uffs_TreeInsertToErasedListTail(dev, newNode);
+		}
+	}
+	else {
+		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
+		uffs_FlashEraseBlock(dev, newBlock);
+		newNode->u.list.block = newBlock;
+		if (HAVE_BADBLOCK(dev))
+			uffs_BadBlockProcess(dev, newNode);
+		else
+			uffs_TreeInsertToErasedListTail(dev, newNode);
+	}
+
+	if (dev->buf.dirtyGroup[slot].dirty != NULL || dev->buf.dirtyGroup[slot].count != 0) {
+		uffs_Perror(UFFS_ERR_NORMAL, "still has dirty buffer ?");
+	}
+
+	uffs_BlockInfoPut(dev, newBc);
+ext:
+	uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+	return (succRecover == U_TRUE ? U_SUCC : U_FAIL);
+
+}
+
+
+
+/** 
+ * \brief flush buffer to a new block which is not registered in tree
+ *
+ * Scenario:
+ *		1. get a new block
+ *		2. write pages in dirty list to new block, sorted by page_id
+ *		3. insert new block to tree
+ */
+static URET _BufFlush_NewBlock(uffs_Device *dev, int slot)
+{
+	u8 type;
+	TreeNode *node;
+	uffs_BlockInfo *bc;
+	URET ret;
+
+	ret = U_FAIL;
+
+	node = uffs_TreeGetErasedNode(dev);
+	if (node == NULL) {
+		uffs_Perror(UFFS_ERR_NOISY, "no erased block!");
+		goto ext;
+	}
+	bc = uffs_BlockInfoGet(dev, node->u.list.block);
+	if (bc == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail!");
+		uffs_InsertToErasedListHead(dev, node); //put node back to erased list
+		goto ext;
+	}
+
+	type = dev->buf.dirtyGroup[slot].dirty->type;
+	
+	ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
+
+	if (ret == U_SUCC)
+		uffs_InsertNodeToTree(dev, type, node);
+	else {
+		uffs_FlashEraseBlock(dev, bc->block);
+		uffs_InsertToErasedListHead(dev, node);
+	}		
+
+	uffs_BlockInfoPut(dev, bc);
+ext:
+	return ret;
+}
+
+
+/** 
+ * \brief flush buffer to a block with enough free pages 
+ *  
+ *  pages in dirty list must be sorted by page_id to write to flash
+ */
+static
+URET
+ uffs_BufFlush_Exist_With_Enough_FreePage(
+		uffs_Device *dev,
+		int slot,			//!< dirty group slot
+		TreeNode *node,		//!< tree node
+		uffs_BlockInfo *bc, //!< block info (Source, also destination)
+		u16 freePages		//!< how many free pages left on destination block
+		)		
+{
+	u16 page;
+	uffs_Buf *buf;
+	uffs_Tags *tag;
+	URET ret;
+	int x;
+
+//	uffs_Perror(UFFS_ERR_NOISY, "Flush buffers with Enough Free Page, in block %d",
+//							bc->block);
+	ret = U_FAIL;
+	for (page = dev->attr->pages_per_block - freePages;	//page: free page num
+			dev->buf.dirtyGroup[slot].count > 0;		//still has dirty pages?
+			page++) {
+
+		buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirtyGroup[slot].dirty);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "count > 0, but no dirty pages in list ?");
+			goto ext;
+		}
+
+		//writre the dirty page (id: buf->page_id) to page i (free page)
+		uffs_BlockInfoLoad(dev, bc, page);
+		tag = GET_TAG(bc, page);
+		TAG_BLOCK_TS(tag) = uffs_GetBlockTimeStamp(dev, bc);
+		TAG_DATA_LEN(tag) = buf->data_len;
+		TAG_TYPE(tag) = buf->type;
+		//tag->data_sum = _GetDirOrFileNameSum(dev, buf);
+		TAG_PARENT(tag) = buf->parent;
+		TAG_SERIAL(tag) = buf->serial;
+		TAG_PAGE_ID(tag) = (u8)(buf->page_id);
+
+		x = uffs_FlashWritePageCombine(dev, bc->block, page, buf, tag);
+		if (x == UFFS_FLASH_IO_ERR) {
+			uffs_Perror(UFFS_ERR_NORMAL, "I/O error <1>?");
+			goto ext;
+		}
+		else if (x == UFFS_FLASH_BAD_BLK) {
+			ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
+			goto ext;
+		}
+		else {
+			if(_BreakFromDirty(dev, buf) == U_SUCC) {
+				buf->mark = UFFS_BUF_VALID;
+				_MoveNodeToHead(dev, buf);
+			}
+		}
+	} //end of for
+	
+	if (dev->buf.dirtyGroup[slot].dirty != NULL || dev->buf.dirtyGroup[slot].count != 0) {
+		uffs_Perror(UFFS_ERR_NORMAL, "still has dirty buffer ?");
+	}
+	else {
+		ret = U_SUCC;
+	}
+
+ext:
+	return ret;
+}
+
+
+URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot)
+{
+	uffs_Buf *dirty;
+	TreeNode *node;
+	uffs_BlockInfo *bc;
+	u16 n;
+	URET ret;
+	u8 type;
+	u16 parent;
+	u16 serial;
+	int block;
+	
+	if (dev->buf.dirtyGroup[slot].count == 0) {
+		return U_SUCC;
+	}
+
+	dirty = dev->buf.dirtyGroup[slot].dirty;
+
+	if (_CheckDirtyList(dirty) == U_FAIL)
+		return U_FAIL;
+
+	type = dirty->type;
+	parent = dirty->parent;
+	serial = dirty->serial;
+
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		node = uffs_TreeFindDirNode(dev, serial);
+		break;
+	case UFFS_TYPE_FILE:
+		node = uffs_TreeFindFileNode(dev, serial);
+		break;
+	case UFFS_TYPE_DATA:
+		node = uffs_TreeFindDataNode(dev, parent, serial);
+		break;
+	default:
+		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type");
+		return U_FAIL;
+	}
+
+	if (node == NULL) {
+		//not found in the tree, need to generate a new block
+		ret = _BufFlush_NewBlock(dev, slot);
+	}
+	else {
+		switch (type) {
+		case UFFS_TYPE_DIR:
+			block = node->u.dir.block;
+			break;
+		case UFFS_TYPE_FILE:
+			block = node->u.file.block;
+			break;
+		case UFFS_TYPE_DATA:
+			block = node->u.data.block;
+			break;
+		default:
+			uffs_Perror(UFFS_ERR_SERIOUS, "unknown type.");
+			return U_FAIL;
+		}
+		bc = uffs_BlockInfoGet(dev, block);
+		if(bc == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "get block info fail.");
+			return U_FAIL;
+		}
+		uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
+		n = uffs_GetFreePagesCount(dev, bc);
+
+		if (n >= dev->buf.dirtyGroup[slot].count && !force_block_recover) {
+			//The free pages are enough for the dirty pages
+			ret = uffs_BufFlush_Exist_With_Enough_FreePage(dev, slot, node, bc, n);
+		}
+		else {
+			ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
+		}
+		uffs_BlockInfoPut(dev, bc);
+	}
+
+	return ret;
+}
+
+static int _FindMostDirtyGroup(struct uffs_DeviceSt *dev)
+{
+	int i, slot = -1;
+	int max_count = 0;
+
+	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
+		if (dev->buf.dirtyGroup[i].dirty && dev->buf.dirtyGroup[i].lock == 0) {
+			if (dev->buf.dirtyGroup[i].count > max_count) {
+				max_count = dev->buf.dirtyGroup[i].count;
+				slot = i;
+			}
+		}
+	}
+
+	return slot;
+}
+
+/** lock dirty group */
+URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot)
+{
+	URET ret = U_FAIL;
+	if (slot >= 0 && slot < MAX_DIRTY_BUF_GROUPS) {
+		dev->buf.dirtyGroup[slot].lock++;
+		ret = U_SUCC;
+	}	
+	return ret;
+}
+
+/** unlock dirty group */
+URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot)
+{
+	URET ret = U_FAIL;
+
+	if (slot >= 0 && slot < MAX_DIRTY_BUF_GROUPS) {
+		if (dev->buf.dirtyGroup[slot].lock > 0)
+			dev->buf.dirtyGroup[slot].lock--;
+		else {
+			uffs_Perror(UFFS_ERR_SERIOUS, "Try to unlock an unlocked group ?");
+		}
+		ret = U_SUCC;
+	}	
+	return ret;
+}
+
+
+/** 
+ * flush buffers to flash.
+ * this will flush all dirty groups.
+ * \param[in] dev uffs device
+ */
+URET uffs_BufFlush(struct uffs_DeviceSt *dev)
+{
+	int slot;
+
+	slot = uffs_BufFindFreeGroupSlot(dev);
+	if (slot >= 0)
+		return U_SUCC;	// do nothing if there is free slot
+	else
+		return uffs_BufFlushMostDirtyGroup(dev);
+}
+
+/** 
+ * flush most dirty group
+ * \param[in] dev uffs device
+ */
+URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev)
+{
+	int slot;
+
+	slot = _FindMostDirtyGroup(dev);
+	if (slot >= 0) {
+		return _BufFlush(dev, U_FALSE, slot);
+	}
+	return U_SUCC;
+}
+
+/** 
+ * flush buffers to flash
+ * this will pick up a most dirty group, and flush it if there is no free dirty group slot.
+ * \param[in] dev uffs device
+ * \param[in] force_block_recover #U_TRUE: force a block recover even there are enough free pages
+ */
+URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
+{
+	int slot;
+
+	slot = uffs_BufFindFreeGroupSlot(dev);
+	if (slot >= 0) {
+		return U_SUCC;  //there is free slot, do nothing.
+	}
+	else {
+		slot = _FindMostDirtyGroup(dev);
+		return _BufFlush(dev, force_block_recover, slot);
+	}
+}
+
+/**
+ * flush buffer group with given parent/serial num.
+ *
+ * \param[in] dev uffs device
+ * \param[in] parent parent num of the group
+ * \param[in] serial serial num of the group
+ */
+URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
+{
+	int slot;
+
+	slot = uffs_BufFindGroupSlot(dev, parent, serial);
+	if (slot >= 0) {
+		return _BufFlush(dev, U_FALSE, slot);
+	}
+
+	return U_SUCC;
+}
+
+/**
+ * flush buffer group with given parent/serial num and force_block_recover indicator.
+ *
+ * \param[in] dev uffs device
+ * \param[in] parent parent num of the group
+ * \param[in] serial serial num of group
+ * \param[in] force_block_recover indicator
+ */
+URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev, u16 parent, u16 serial, UBOOL force_block_recover)
+{
+	int slot;
+
+	slot = uffs_BufFindGroupSlot(dev, parent, serial);
+	if (slot >= 0) {
+		return _BufFlush(dev, force_block_recover, slot);
+	}
+
+	return U_SUCC;
+}
+
+
+/**
+ * flush buffer group/groups which match given parent num.
+ *
+ * \param[in] dev uffs device
+ * \param[in] parent parent num of the group
+ * \param[in] serial serial num of group
+ * \param[in] force_block_recover indicator
+ */
+URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent)
+{
+	int slot;
+	uffs_Buf *buf;
+	URET ret = U_SUCC;
+
+	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS && ret == U_SUCC; slot++) {
+		if (dev->buf.dirtyGroup[slot].dirty) {
+			buf = dev->buf.dirtyGroup[slot].dirty;
+			if (buf->parent == parent) {
+				ret = _BufFlush(dev, U_FALSE, slot);
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * find a free dirty group slot
+ *
+ * \param[in] dev uffs device
+ * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one, otherwise return -1.
+ */
+int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev)
+{
+	int i, slot = -1;
+
+	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
+		if (dev->buf.dirtyGroup[i].dirty == NULL) {
+			slot = i;
+			break;
+		}
+	}
+	return slot;
+}
+
+/**
+ * find a dirty group slot with given parent/serial num.
+ *
+ * \param[in] dev uffs device
+ * \param[in] parent parent num of the group
+ * \param[in] serial serial num of group
+ * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one, otherwise return -1.
+ */
+int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
+{
+	uffs_Buf *buf;
+	int i, slot = -1;
+
+	for (i = 0; i < MAX_DIRTY_BUF_GROUPS; i++) {
+		if (dev->buf.dirtyGroup[i].dirty) {
+			buf = dev->buf.dirtyGroup[i].dirty;
+			if (buf->parent == parent && buf->serial == serial) {
+				slot = i;
+				break;
+			}
+		}
+	}
+	return slot;
+}
+
+/** 
+ * \brief get a page buffer
+ * \param[in] dev uffs device
+ * \param[in] parent parent serial num
+ * \param[in] serial serial num
+ * \param[in] page_id page_id
+ * \return return the buffer found in buffer list, if not found, return NULL.
+ */
+uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 parent, u16 serial, u16 page_id)
+{
+	uffs_Buf *p;
+
+	//first, check whether the buffer exist in buf list ?
+	p = uffs_BufFind(dev, parent, serial, page_id);
+
+	if (p) {
+		p->ref_count++;
+		_MoveNodeToHead(dev, p);
+	}
+
+	return p;
+}
+
+/** 
+ * New generate a buffer
+ */
+uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 parent, u16 serial, u16 page_id)
+{
+	uffs_Buf *buf;
+
+	buf = uffs_BufGet(dev, parent, serial, page_id);
+	if (buf) {
+		if (buf->ref_count > 1) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "When create new buf, an exist buffer has ref count %d, possibly bug!", buf->ref_count);
+		}
+		else {
+			buf->data_len = 0;
+		}
+		_MoveNodeToHead(dev, buf);
+		return buf;
+	}
+
+	buf = _FindFreeBuf(dev);
+	if (buf == NULL) {
+		uffs_BufFlushMostDirtyGroup(dev);
+		buf = _FindFreeBuf(dev);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "no free page buf!");
+			return NULL;
+		}
+	}
+
+	buf->mark = UFFS_BUF_EMPTY;
+	buf->type = type;
+	buf->parent = parent;
+	buf->serial = serial;
+	buf->page_id = page_id;
+	buf->data_len = 0;
+	buf->ref_count++;
+	memset(buf->data, 0xff, dev->com.pg_data_size);
+
+	_MoveNodeToHead(dev, buf);
+	
+	return buf;	
+}
+
+
+
+/** 
+ * get a page buffer
+ * \param[in] dev uffs device
+ * \param[in] type dir, file or data ?
+ * \param[in] node node on the tree
+ * \param[in] page_id page_id
+ * \return return the buffer if found in buffer list, if not found in 
+ *			buffer list, it will get a free buffer, and load data from flash.
+ *			return NULL if not free buffer.
+ */
+uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 page_id)
+{
+	uffs_Buf *buf;
+	u16 parent, serial, block, page;
+	uffs_BlockInfo *bc;
+
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		parent = node->u.dir.parent;
+		serial = node->u.dir.serial;
+		block = node->u.dir.block;
+		break;
+	case UFFS_TYPE_FILE:
+		parent = node->u.file.parent;
+		serial = node->u.file.serial;
+		block = node->u.file.block;
+		break;
+	case UFFS_TYPE_DATA:
+		parent = node->u.data.parent;
+		serial = node->u.data.serial;
+		block = node->u.data.block;
+		break;
+	default:
+		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type");
+		return NULL;
+	}
+
+	buf = uffs_BufFind(dev, parent, serial, page_id);
+	if (buf) {
+		buf->ref_count++;
+		return buf;
+	}
+
+	buf = _FindFreeBuf(dev);
+	if (buf == NULL) {
+		uffs_BufFlushMostDirtyGroup(dev);
+		buf = _FindFreeBuf(dev);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "no free page buf!");
+			return NULL;
+		}
+	}
+
+	bc = uffs_BlockInfoGet(dev, block);
+	if (bc == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "Can't get block info!");
+		return NULL;
+	}
+	
+	page = uffs_FindPageInBlockWithPageId(dev, bc, page_id);
+	if (page == UFFS_INVALID_PAGE) {
+		uffs_BlockInfoPut(dev, bc);
+		uffs_Perror(UFFS_ERR_SERIOUS, "can't find right page ?");
+		return NULL;
+	}
+	page = uffs_FindBestPageInBlock(dev, bc, page);
+	uffs_BlockInfoPut(dev, bc);
+
+	buf->mark = UFFS_BUF_EMPTY;
+	buf->type = type;
+	buf->parent = parent;
+	buf->serial = serial;
+	buf->page_id = page_id;
+
+	if (UFFS_FLASH_HAVE_ERR(uffs_FlashReadPage(dev, block, page, buf))) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "can't load page from flash !");
+		return NULL;
+	}
+
+	buf->data_len = TAG_DATA_LEN(GET_TAG(bc, page));
+	buf->mark = UFFS_BUF_VALID;
+	buf->ref_count++;
+
+	_MoveNodeToHead(dev, buf);
+	
+	return buf;
+
+}
+
+/** 
+ * \brief Put back a page buffer, make reference count decrease by one
+ * \param[in] dev uffs device
+ * \param[in] buf buffer to be put back
+ */
+URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
+{
+	URET ret = U_FAIL;
+
+	dev = dev;
+	if (buf == NULL) {
+		uffs_Perror(UFFS_ERR_NORMAL,  "Can't put an NULL buffer!");
+	}
+	else if (buf->ref_count == 0) {
+		uffs_Perror(UFFS_ERR_NORMAL,  "Putting an unused page buffer ? ");
+	}
+	else if (buf->ref_count == CLONE_BUF_MARK) {
+		uffs_Perror(UFFS_ERR_NORMAL, "Putting an cloned page buffer ? ");
+		ret = uffs_BufFreeClone(dev, buf);
+	}
+	else {
+		buf->ref_count--;
+		ret = U_SUCC;
+	}
+
+	return ret;
+}
+
+
+/** 
+ * \brief clone from an exist buffer.
+		allocate memory for new buffer, and copy data from original buffer if 
+		original buffer is not NULL. 
+ * \param[in] dev uffs device
+ * \param[in] buf page buffer to be clone from. if NULL presented here, data copy will not be processed
+ * \return return the cloned page buffer, all data copied from source
+ * \note the cloned buffer is not linked in page buffer list in uffs device,
+ *			so you should use #uffs_BufFreeClone instead of #uffs_BufPut when you put back or release buffer
+ */
+uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
+{
+	uffs_Buf *p;
+
+	p = _FindFreeBufEx(dev, 1);
+	if (p == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "no enough free pages for clone! Please increase Clone Buffer Count threshold.");
+	}
+	else {
+		_BreakFromBufList(dev, p);
+
+		if (buf) {
+			p->parent = buf->parent;
+			p->type = buf->type;
+			p->serial = buf->serial;
+			p->page_id = buf->page_id;
+			
+			p->data_len = buf->data_len;
+			//athough the valid data length is .data_len,
+			//but we still need copy the whole buffer, include header
+			memcpy(p->header, buf->header, dev->com.pg_size);
+		}
+		p->next = p->prev = NULL;			//because the cloned one is not linked to device buffer
+		p->next_dirty = p->prev_dirty = NULL;
+		p->ref_count = CLONE_BUF_MARK;		//CLONE_BUF_MARK indicates that this is an cloned buffer
+	}
+
+	return p;
+}
+
+/** 
+ * \brief release cloned buffer
+ * \param[in] dev uffs device
+ * \param[in] buf cloned buffer
+ */
+URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
+{
+	dev = dev; //make compiler happy
+	if (!buf)
+		return U_FAIL;
+
+	if (buf->ref_count != CLONE_BUF_MARK) {
+		/* a cloned buffer must have a ref_count of CLONE_BUF_MARK */
+		uffs_Perror(UFFS_ERR_SERIOUS,  "Try to release a non-cloned page buffer ?");
+		return U_FAIL;
+	}
+
+	buf->ref_count = 0;
+	buf->mark = UFFS_BUF_EMPTY;
+	_LinkToBufListTail(dev, buf);
+
+	return U_SUCC;
+}
+
+
+
+UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
+{
+	uffs_Buf *buf = dev->buf.head;
+
+	while (buf) {
+		if(buf->ref_count != 0) return U_FALSE;
+		buf = buf->next;
+	}
+
+	return U_TRUE;
+}
+
+UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
+{
+	uffs_Buf *buf = dev->buf.head;
+
+	while (buf) {
+		if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
+		buf = buf->next;
+	}
+
+	return U_TRUE;
+}
+
+
+URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
+{
+	uffs_Buf *buf = dev->buf.head;
+
+	while (buf) {
+		buf->mark = UFFS_BUF_EMPTY;
+		buf = buf->next;
+	}
+	return U_SUCC;
+}
+
+
+void uffs_BufIncRef(uffs_Buf *buf)
+{
+	buf->ref_count++;
+}
+
+void uffs_BufDecRef(uffs_Buf *buf)
+{
+	if (buf->ref_count > 0)
+		buf->ref_count--;
+}
+
+/** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0, and discard all data it holds */
+void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf)
+{
+	if (buf->mark != UFFS_BUF_EMPTY) {
+		if (buf->ref_count == 0) {
+			if (buf->mark == UFFS_BUF_DIRTY)
+				_BreakFromDirty(dev, buf);
+			buf->mark = UFFS_BUF_EMPTY;
+		}
+	}
+}
+
+#if 0
+static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
+{
+	uffs_Buf *p = dev->buf.dirtyGroup[slot].dirty;
+
+	while (p) {
+		if(p == buf) return U_TRUE;
+		p = p->next_dirty;
+	}
+
+	return U_FALSE;
+}
+#endif
+
+URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
+{
+	int slot;
+
+	if(ofs + len > dev->com.pg_data_size) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "data length out of range! %d+%d", ofs, len);
+		return U_FAIL;
+	}
+
+	slot = uffs_BufFindGroupSlot(dev, buf->parent, buf->serial);
+
+	if (slot < 0) {
+		// need to take a free slot
+		slot = uffs_BufFindFreeGroupSlot(dev);
+		if (slot < 0) {
+			// no free slot ? flush buffer
+			if (uffs_BufFlushMostDirtyGroup(dev) != U_SUCC)
+				return U_FAIL;
+
+			slot = uffs_BufFindFreeGroupSlot(dev);
+			if (slot < 0) {
+				// still no free slot ??
+				uffs_Perror(UFFS_ERR_SERIOUS, "no free slot ?");
+				return U_FAIL;
+			}
+		}
+	}
+
+	memcpy(buf->data + ofs, data, len);
+
+	if (ofs + len > buf->data_len) 
+		buf->data_len = ofs + len;
+	
+	if (_IsBufInInDirtyList(dev, slot, buf) == U_FALSE) {
+		_LinkToDirtyList(dev, slot, buf);
+	}
+
+	if (dev->buf.dirtyGroup[slot].count >= dev->buf.dirty_buf_max) {
+		if (uffs_BufFlushGroup(dev, buf->parent, buf->serial) != U_SUCC) {
+			return U_FAIL;
+		}
+	}
+
+	return U_SUCC;
+}
+
+URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
+{
+	u32 readSize;
+	u32 pg_data_size = dev->com.pg_data_size;
+
+	readSize = (ofs >= pg_data_size ? 0 : (ofs + len >= pg_data_size ? pg_data_size - ofs : len));
+
+	if (readSize > 0) 
+		memcpy(data, buf->data + ofs, readSize);
+
+	return U_SUCC;
+}
+
+
+
+
+
+
+

+ 144 - 144
components/dfs/filesystems/uffs/src/uffs/uffs_debug.c

@@ -1,144 +1,144 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_debug.c
- * \brief output debug messages
- * \author Ricky Zheng, created 10th May, 2005
- */
-#include "uffs/uffs_public.h"
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-
-#if !defined(_UBASE_)
-#define ENABLE_DEBUG
-//#define OUTPUT_TOFILE
-#endif
-
-#if !defined(_UBASE_)
-
-
-#ifdef OUTPUT_TOFILE
-#define DEBUG_LOGFILE	"log.txt"
-#endif
-
-void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...)
-{
-
-#ifdef ENABLE_DEBUG
-	if (level >= UFFS_DBG_LEVEL) {
-
-		char buf[1024] = {0};
-		char *p;
-		
-
-#ifdef OUTPUT_TOFILE
-		FILE *fp = NULL;	
-#endif
-		
-		va_list arg;
-
-		if (strlen(errFmt) > 800) {
-			// dangerous!!
-			printf("uffs_Perror buffer is not enough !");
-			return;
-		}
-
-		p = buf;
-
-		if (prefix) {
-			strcpy(p, prefix);
-			p += strlen(prefix);
-		}
-
-		va_start(arg, errFmt);
-		vsprintf(p, errFmt, arg);
-		va_end(arg);
-
-		if (suffix)
-			strcat(p, suffix);
-
-#ifdef OUTPUT_TOFILE
-		fp = fopen(DEBUG_LOGFILE, "a+b");
-		if (fp) {
-			fwrite(buf, 1, strlen(buf), fp);
-			fclose(fp);
-		}
-#else
-		printf("%s", buf);
-#endif
-	}
-#endif //ENABLE_DEBUG
-}
-
-#else
-
-#define ENABLE_DEBUG
-
-#include <uBase.h>
-#include <sys/debug.h>
-
-
-void uffs_Perror( int level, const char *errFmt, ...)
-{
-#ifdef ENABLE_DEBUG
-	va_list args;
-	if (level >= UFFS_DBG_LEVEL) {
-		va_start(args, errFmt);
-		//uffs_vTrace(errFmt, args);
-		dbg_simple_vprintf(errFmt, args);
-		va_end(args);
-	}
-	dbg_simple_raw(TENDSTR);
-#else
-	level = level;
-	errFmt = errFmt;
-#endif //ENABLE_DEBUG
-}
-
-#endif
-
-/**
- * \brief Called when an assert occurred.
- * This method is called when an assert occurred and should stop the
- * application from running, as this there is a severe error condition.
- * \param[in] file Source filename
- * \param[in] line Source line of code
- * \param[in] msg Assert message
- */
-void uffs_AssertCall(const char *file, int line, const char *msg)
-{
-	printf("ASSERT %s:%d - msg:%s\n", file, line, msg);
-	while (1);
-}
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_debug.c
+ * \brief output debug messages
+ * \author Ricky Zheng, created 10th May, 2005
+ */
+#include "uffs/uffs_public.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+
+#if !defined(_UBASE_)
+#define ENABLE_DEBUG
+//#define OUTPUT_TOFILE
+#endif
+
+#if !defined(_UBASE_)
+
+
+#ifdef OUTPUT_TOFILE
+#define DEBUG_LOGFILE	"log.txt"
+#endif
+
+void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...)
+{
+
+#ifdef ENABLE_DEBUG
+	if (level >= UFFS_DBG_LEVEL) {
+
+		char buf[1024] = {0};
+		char *p;
+		
+
+#ifdef OUTPUT_TOFILE
+		FILE *fp = NULL;	
+#endif
+		
+		va_list arg;
+
+		if (strlen(errFmt) > 800) {
+			// dangerous!!
+			rt_kprintf("uffs_Perror buffer is not enough !");
+			return;
+		}
+
+		p = buf;
+
+		if (prefix) {
+			strcpy(p, prefix);
+			p += strlen(prefix);
+		}
+
+		va_start(arg, errFmt);
+		vsprintf(p, errFmt, arg);
+		va_end(arg);
+
+		if (suffix)
+			strcat(p, suffix);
+
+#ifdef OUTPUT_TOFILE
+		fp = fopen(DEBUG_LOGFILE, "a+b");
+		if (fp) {
+			fwrite(buf, 1, strlen(buf), fp);
+			fclose(fp);
+		}
+#else
+		rt_kprintf("%s", buf);
+#endif
+	}
+#endif //ENABLE_DEBUG
+}
+
+#else
+
+#define ENABLE_DEBUG
+
+#include <uBase.h>
+#include <sys/debug.h>
+
+
+void uffs_Perror( int level, const char *errFmt, ...)
+{
+#ifdef ENABLE_DEBUG
+	va_list args;
+	if (level >= UFFS_DBG_LEVEL) {
+		va_start(args, errFmt);
+		//uffs_vTrace(errFmt, args);
+		dbg_simple_vprintf(errFmt, args);
+		va_end(args);
+	}
+	dbg_simple_raw(TENDSTR);
+#else
+	level = level;
+	errFmt = errFmt;
+#endif //ENABLE_DEBUG
+}
+
+#endif
+
+/**
+ * \brief Called when an assert occurred.
+ * This method is called when an assert occurred and should stop the
+ * application from running, as this there is a severe error condition.
+ * \param[in] file Source filename
+ * \param[in] line Source line of code
+ * \param[in] msg Assert message
+ */
+void uffs_AssertCall(const char *file, int line, const char *msg)
+{
+	rt_kprintf("ASSERT %s:%d - msg:%s\n", file, line, msg);
+	while (1);
+}

+ 94 - 94
components/dfs/filesystems/uffs/src/uffs/uffs_device.c

@@ -1,94 +1,94 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_device.c
- * \brief uffs device operation
- * \author Ricky Zheng, created 10th May, 2005
- */
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_mtb.h"
-#include <string.h>
-
-#define PFX "dev: "
-
-
-
-URET uffs_DeviceInitLock(uffs_Device *dev)
-{
-	dev->lock.sem = uffs_SemCreate(1);
-	dev->lock.task_id = UFFS_TASK_ID_NOT_EXIST;
-	dev->lock.counter = 0;
-
-	return U_SUCC;
-}
-
-URET uffs_DeviceReleaseLock(uffs_Device *dev)
-{
-	if (dev->lock.sem) {
-		uffs_SemDelete(dev->lock.sem);
-		dev->lock.sem = 0;
-	}
-
-	return U_SUCC;
-}
-
-URET uffs_DeviceLock(uffs_Device *dev)
-{
-
-	uffs_SemWait(dev->lock.sem);
-	
-	if (dev->lock.counter != 0) {
-		uffs_Perror(UFFS_ERR_NORMAL, "Lock device, counter %d NOT zero?!", dev->lock.counter);
-	}
-
-	dev->lock.counter++;
-
-	return U_SUCC;
-}
-
-URET uffs_DeviceUnLock(uffs_Device *dev)
-{
-
-	dev->lock.counter--;
-
-	if (dev->lock.counter != 0) {
-		uffs_Perror(UFFS_ERR_NORMAL, "Unlock device, counter %d NOT zero?!", dev->lock.counter);
-	}
-	
-	uffs_SemSignal(dev->lock.sem);
-
-	return U_SUCC;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_device.c
+ * \brief uffs device operation
+ * \author Ricky Zheng, created 10th May, 2005
+ */
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_mtb.h"
+#include <string.h>
+
+#define PFX "dev: "
+
+
+
+URET uffs_DeviceInitLock(uffs_Device *dev)
+{
+	dev->lock.sem = uffs_SemCreate(1);
+	dev->lock.task_id = UFFS_TASK_ID_NOT_EXIST;
+	dev->lock.counter = 0;
+
+	return U_SUCC;
+}
+
+URET uffs_DeviceReleaseLock(uffs_Device *dev)
+{
+	if (dev->lock.sem) {
+		uffs_SemDelete(dev->lock.sem);
+		dev->lock.sem = 0;
+	}
+
+	return U_SUCC;
+}
+
+URET uffs_DeviceLock(uffs_Device *dev)
+{
+
+	uffs_SemWait(dev->lock.sem);
+	
+	if (dev->lock.counter != 0) {
+		uffs_Perror(UFFS_ERR_NORMAL, "Lock device, counter %d NOT zero?!", dev->lock.counter);
+	}
+
+	dev->lock.counter++;
+
+	return U_SUCC;
+}
+
+URET uffs_DeviceUnLock(uffs_Device *dev)
+{
+
+	dev->lock.counter--;
+
+	if (dev->lock.counter != 0) {
+		uffs_Perror(UFFS_ERR_NORMAL, "Unlock device, counter %d NOT zero?!", dev->lock.counter);
+	}
+	
+	uffs_SemSignal(dev->lock.sem);
+
+	return U_SUCC;
+}
+

+ 357 - 357
components/dfs/filesystems/uffs/src/uffs/uffs_ecc.c

@@ -1,357 +1,357 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_ecc.c
- * \brief ecc maker and correct
- * \author Ricky Zheng, created in 12th Jun, 2005
- */
-
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_config.h"
-#include <string.h>
-
-#define PFX "ecc: "
-
-static const u8 bits_tbl[256] = {
-	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
-};
-
-static const u8 line_parity_tbl[16] = {
-	0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a, 0x80, 0x82, 0x88, 0x8a, 0xa0, 0xa2, 0xa8, 0xaa
-};
-
-static const u8 line_parity_prime_tbl[16] = {
-	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55
-};
-
-static const u8 column_parity_tbl[256] = {
-	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
-	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
-	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
-	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
-	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
-	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
-	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
-	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
-	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
-	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
-	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
-	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
-	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
-	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
-	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
-	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
-};
-
-/**
- * calculate 3 bytes ECC for 256 bytes data.
- *
- * \param[in] data input data
- * \param[out] ecc output ecc
- * \param[in] length of data in bytes
- */
-static void uffs_EccMakeChunk256(void *data, void *ecc, u16 len)
-{
-	u8 *pecc = (u8 *)ecc;
-	u8 *p = (u8 *)data;
-	u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
-	u16 i;
-
-	for (i = 0; i < len; i++) {
-		b = column_parity_tbl[*p++];
-		col_parity ^= b;
-		if (b & 0x01) { // odd number of bits in the byte
-			line_parity ^= i;
-			line_parity_prime ^= ~i;
-		}
-	}
-
-	// ECC layout:
-	// Byte[0]  P64   | P64'   | P32  | P32'  | P16  | P16'  | P8   | P8'
-	// Byte[1]  P1024 | P1024' | P512 | P512' | P256 | P256' | P128 | P128'
-	// Byte[2]  P4    | P4'    | P2   | P2'   | P1   | P1'   | 1    | 1
-	pecc[0] = ~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf]);
-	pecc[1] = ~(line_parity_tbl[line_parity >> 4] | line_parity_prime_tbl[line_parity_prime >> 4]);
-	pecc[2] = (~col_parity) | 0x03;
-
-}
-
-
-/**
- * calculate ECC. (3 bytes ECC per 256 data)
- *
- * \param[in] data input data
- * \param[in] data_len length of data in byte
- * \param[out] ecc output ecc
- *
- * \return length of ECC in byte. (3 bytes ECC per 256 data) 
- */
-int uffs_EccMake(void *data, int data_len, void *ecc)
-{
-	u8 *p_data = (u8 *)data, *p_ecc = (u8 *)ecc;
-	int len;
-
-	if (data == NULL || ecc == NULL)
-		return 0;
-
-	while (data_len > 0) {
-		len = data_len > 256 ? 256 : data_len;
-		uffs_EccMakeChunk256(p_data, p_ecc, len);
-		data_len -= len;
-		p_data += len;
-		p_ecc += 3;
-	}
-
-	return p_ecc - (u8 *)ecc;
-}
-
-/**
- * perform ECC error correct for 256 bytes data chunk.
- *
- * \param[in|out] data input data to be corrected
- * \param[in] read_ecc 3 bytes ECC read from storage
- * \param[in] test_ecc 3 bytes ECC calculated from data
- * \param[in] errtop top position of error
- *
- * \return:  0 -- no error
- *			-1 -- can not be corrected
- *			>0 -- how many bits corrected
- */
-static int uffs_EccCorrectChunk256(void *data, void *read_ecc, const void *test_ecc, int errtop)
-{
-	u8 d0, d1, d2;		/* deltas */
-	u8 *p = (u8 *)data;
-	u8 *pread_ecc = (u8 *)read_ecc, *ptest_ecc = (u8 *)test_ecc;
-
-	d0 = pread_ecc[0] ^ ptest_ecc[0];
-	d1 = pread_ecc[1] ^ ptest_ecc[1];
-	d2 = pread_ecc[2] ^ ptest_ecc[2];
-	
-	if ((d0 | d1 | d2) == 0)
-		return 0;
-	
-	if( ((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
-	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
-	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54)
-	{
-		// Single bit (recoverable) error in data
-
-		u8 b;
-		u8 bit;
-		
-		bit = b = 0;		
-		
-		if(d1 & 0x80) b |= 0x80;
-		if(d1 & 0x20) b |= 0x40;
-		if(d1 & 0x08) b |= 0x20;
-		if(d1 & 0x02) b |= 0x10;
-		if(d0 & 0x80) b |= 0x08;
-		if(d0 & 0x20) b |= 0x04;
-		if(d0 & 0x08) b |= 0x02;
-		if(d0 & 0x02) b |= 0x01;
-
-		if(d2 & 0x80) bit |= 0x04;
-		if(d2 & 0x20) bit |= 0x02;
-		if(d2 & 0x08) bit |= 0x01;
-
-		if (b >= errtop) return -1;
-
-		p[b] ^= (1 << bit);
-		
-		return 1;
-	}
-	
-	if ((bits_tbl[d0] + bits_tbl[d1] + bits_tbl[d2]) == 1) {
-		// error in ecc, no action need		
-		return 1;
-	}
-	
-	// Unrecoverable error
-	return -1;
-}
-
-/**
- * perform ECC error correct
- *
- * \param[in|out] data input data to be corrected
- * \param[in] data_len length of data in byte
- * \param[in] read_ecc ECC read from storage
- * \param[in] test_ecc ECC calculated from data
- *
- * \return:  0 -- no error
- *			-1 -- can not be corrected
- *			>0 -- how many bits corrected
- */
-
-int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc)
-{
-	u8 *p_data = (u8 *)data, *p_read_ecc = (u8 *)read_ecc, *p_test_ecc = (u8 *)test_ecc;
-	int total = 0, ret, len;
-
-	if (data == NULL || read_ecc == NULL || test_ecc == NULL)
-		return -1;
-
-	while (data_len > 0) {
-		len = (data_len > 256 ? 256 : data_len);
-		ret = uffs_EccCorrectChunk256(p_data, p_read_ecc, p_test_ecc, len);
-		if (ret < 0) {
-			total = ret;
-			break;
-		}
-		else
-			total += ret;
-
-		p_data += len;
-		p_read_ecc += 3;
-		p_test_ecc += 3;
-		data_len -= len;
-	}
-
-	return total;
-
-}
-
-/** 
- * generate 12 bit ecc for 8 bytes data. 
- *	(use 0xFF padding if the data length is less then 8 bytes)
- *
- * \param[in] data input data
- * \param[in] data_len length of data in byte
- *
- * \return 12 bits ECC data (lower 12 bits).
- */
-u16 uffs_EccMake8(void *data, int data_len)
-{
-	u8 *p = (u8 *)data;
-	u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
-	u8 i;
-	u16 ecc = 0;
-
-
-	data_len = (data_len > 8 ? 8 : data_len);
-
-	for (i = 0; i < data_len; i++) {
-		b = column_parity_tbl[*p++];
-		col_parity ^= b;
-		if (b & 0x01) { // odd number of bits in the byte
-			line_parity ^= i;
-			line_parity_prime ^= ~i;
-		}
-	}
-
-	// ECC layout:
-	// row:         (1)  | (1)   | P32  | P32'  | P16  | P16'  | P8   | P8'
-	// column:      P4   | P4'   | P2   | P2'   | P1   | P1'   | (1)  | (1)
-	// 12-bit ecc:  P32  | P32'  | P16  | P16'  | P8   | P8'   | P4   | P4'   | P2   | P2'   | P1   | P1'  |
-	ecc = (~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf])) << 6;
-	ecc |= (((~col_parity) >> 2) & 0x3f);
-
-	return ecc & 0xfff;
-}
-
-/**
- * correct 8 bytes data from 12 bits ECC
- *
- * \param[in|out] data input data
- * \param[in] read_ecc ecc read from storage
- * \param[in] test_ecc ecc calculated from data
- * \param[in] errtop top position of error.
- *
- * \return:  0 -- no error
- *			-1 -- can not be corrected
- *			>0 -- how many bits corrected
- */
-int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop)
-{
-	u8 d0, d1;			/* deltas */
-	u8 *p = (u8 *)data;
-
-	read_ecc &= 0xfff;
-	test_ecc &= 0xfff;
-
-	d0 = (read_ecc >> 6) ^ (test_ecc >> 6);
-	d1 = (read_ecc & 0x3f) ^ (test_ecc & 0x3f);
-
-	if ((d0 | d1) == 0)
-		return 0;
-	
-	if( ((d0 ^ (d0 >> 1)) & 0x15) == 0x15 &&
-	    ((d1 ^ (d1 >> 1)) & 0x15) == 0x15)
-	{
-		// Single bit (recoverable) error in data
-
-		u8 b;
-		u8 bit;
-		
-		bit = b = 0;		
-		
-		if(d0 & 0x20) b |= 0x04;
-		if(d0 & 0x08) b |= 0x02;
-		if(d0 & 0x02) b |= 0x01;
-
-		if(d1 & 0x20) bit |= 0x04;
-		if(d1 & 0x08) bit |= 0x02;
-		if(d1 & 0x02) bit |= 0x01;
-
-		if (b >= (u8)errtop) return -1;
-		if (bit >= 8) return -1;
-
-		p[b] ^= (1 << bit);
-		
-		return 1;
-	}
-	
-	if ((bits_tbl[d0] + bits_tbl[d1]) == 1) {
-		// error in ecc, no action need		
-		return 1;
-	}
-	
-	// Unrecoverable error
-	return -1;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_ecc.c
+ * \brief ecc maker and correct
+ * \author Ricky Zheng, created in 12th Jun, 2005
+ */
+
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_config.h"
+#include <string.h>
+
+#define PFX "ecc: "
+
+static const u8 bits_tbl[256] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
+
+static const u8 line_parity_tbl[16] = {
+	0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a, 0x80, 0x82, 0x88, 0x8a, 0xa0, 0xa2, 0xa8, 0xaa
+};
+
+static const u8 line_parity_prime_tbl[16] = {
+	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55
+};
+
+static const u8 column_parity_tbl[256] = {
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
+};
+
+/**
+ * calculate 3 bytes ECC for 256 bytes data.
+ *
+ * \param[in] data input data
+ * \param[out] ecc output ecc
+ * \param[in] length of data in bytes
+ */
+static void uffs_EccMakeChunk256(void *data, void *ecc, u16 len)
+{
+	u8 *pecc = (u8 *)ecc;
+	u8 *p = (u8 *)data;
+	u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
+	u16 i;
+
+	for (i = 0; i < len; i++) {
+		b = column_parity_tbl[*p++];
+		col_parity ^= b;
+		if (b & 0x01) { // odd number of bits in the byte
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+	}
+
+	// ECC layout:
+	// Byte[0]  P64   | P64'   | P32  | P32'  | P16  | P16'  | P8   | P8'
+	// Byte[1]  P1024 | P1024' | P512 | P512' | P256 | P256' | P128 | P128'
+	// Byte[2]  P4    | P4'    | P2   | P2'   | P1   | P1'   | 1    | 1
+	pecc[0] = ~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf]);
+	pecc[1] = ~(line_parity_tbl[line_parity >> 4] | line_parity_prime_tbl[line_parity_prime >> 4]);
+	pecc[2] = (~col_parity) | 0x03;
+
+}
+
+
+/**
+ * calculate ECC. (3 bytes ECC per 256 data)
+ *
+ * \param[in] data input data
+ * \param[in] data_len length of data in byte
+ * \param[out] ecc output ecc
+ *
+ * \return length of ECC in byte. (3 bytes ECC per 256 data) 
+ */
+int uffs_EccMake(void *data, int data_len, void *ecc)
+{
+	u8 *p_data = (u8 *)data, *p_ecc = (u8 *)ecc;
+	int len;
+
+	if (data == NULL || ecc == NULL)
+		return 0;
+
+	while (data_len > 0) {
+		len = data_len > 256 ? 256 : data_len;
+		uffs_EccMakeChunk256(p_data, p_ecc, len);
+		data_len -= len;
+		p_data += len;
+		p_ecc += 3;
+	}
+
+	return p_ecc - (u8 *)ecc;
+}
+
+/**
+ * perform ECC error correct for 256 bytes data chunk.
+ *
+ * \param[in|out] data input data to be corrected
+ * \param[in] read_ecc 3 bytes ECC read from storage
+ * \param[in] test_ecc 3 bytes ECC calculated from data
+ * \param[in] errtop top position of error
+ *
+ * \return:  0 -- no error
+ *			-1 -- can not be corrected
+ *			>0 -- how many bits corrected
+ */
+static int uffs_EccCorrectChunk256(void *data, void *read_ecc, const void *test_ecc, int errtop)
+{
+	u8 d0, d1, d2;		/* deltas */
+	u8 *p = (u8 *)data;
+	u8 *pread_ecc = (u8 *)read_ecc, *ptest_ecc = (u8 *)test_ecc;
+
+	d0 = pread_ecc[0] ^ ptest_ecc[0];
+	d1 = pread_ecc[1] ^ ptest_ecc[1];
+	d2 = pread_ecc[2] ^ ptest_ecc[2];
+	
+	if ((d0 | d1 | d2) == 0)
+		return 0;
+	
+	if( ((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54)
+	{
+		// Single bit (recoverable) error in data
+
+		u8 b;
+		u8 bit;
+		
+		bit = b = 0;		
+		
+		if(d1 & 0x80) b |= 0x80;
+		if(d1 & 0x20) b |= 0x40;
+		if(d1 & 0x08) b |= 0x20;
+		if(d1 & 0x02) b |= 0x10;
+		if(d0 & 0x80) b |= 0x08;
+		if(d0 & 0x20) b |= 0x04;
+		if(d0 & 0x08) b |= 0x02;
+		if(d0 & 0x02) b |= 0x01;
+
+		if(d2 & 0x80) bit |= 0x04;
+		if(d2 & 0x20) bit |= 0x02;
+		if(d2 & 0x08) bit |= 0x01;
+
+		if (b >= errtop) return -1;
+
+		p[b] ^= (1 << bit);
+		
+		return 1;
+	}
+	
+	if ((bits_tbl[d0] + bits_tbl[d1] + bits_tbl[d2]) == 1) {
+		// error in ecc, no action need		
+		return 1;
+	}
+	
+	// Unrecoverable error
+	return -1;
+}
+
+/**
+ * perform ECC error correct
+ *
+ * \param[in|out] data input data to be corrected
+ * \param[in] data_len length of data in byte
+ * \param[in] read_ecc ECC read from storage
+ * \param[in] test_ecc ECC calculated from data
+ *
+ * \return:  0 -- no error
+ *			-1 -- can not be corrected
+ *			>0 -- how many bits corrected
+ */
+
+int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc)
+{
+	u8 *p_data = (u8 *)data, *p_read_ecc = (u8 *)read_ecc, *p_test_ecc = (u8 *)test_ecc;
+	int total = 0, ret, len;
+
+	if (data == NULL || read_ecc == NULL || test_ecc == NULL)
+		return -1;
+
+	while (data_len > 0) {
+		len = (data_len > 256 ? 256 : data_len);
+		ret = uffs_EccCorrectChunk256(p_data, p_read_ecc, p_test_ecc, len);
+		if (ret < 0) {
+			total = ret;
+			break;
+		}
+		else
+			total += ret;
+
+		p_data += len;
+		p_read_ecc += 3;
+		p_test_ecc += 3;
+		data_len -= len;
+	}
+
+	return total;
+
+}
+
+/** 
+ * generate 12 bit ecc for 8 bytes data. 
+ *	(use 0xFF padding if the data length is less then 8 bytes)
+ *
+ * \param[in] data input data
+ * \param[in] data_len length of data in byte
+ *
+ * \return 12 bits ECC data (lower 12 bits).
+ */
+u16 uffs_EccMake8(void *data, int data_len)
+{
+	u8 *p = (u8 *)data;
+	u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
+	u8 i;
+	u16 ecc = 0;
+
+
+	data_len = (data_len > 8 ? 8 : data_len);
+
+	for (i = 0; i < data_len; i++) {
+		b = column_parity_tbl[*p++];
+		col_parity ^= b;
+		if (b & 0x01) { // odd number of bits in the byte
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+	}
+
+	// ECC layout:
+	// row:         (1)  | (1)   | P32  | P32'  | P16  | P16'  | P8   | P8'
+	// column:      P4   | P4'   | P2   | P2'   | P1   | P1'   | (1)  | (1)
+	// 12-bit ecc:  P32  | P32'  | P16  | P16'  | P8   | P8'   | P4   | P4'   | P2   | P2'   | P1   | P1'  |
+	ecc = (~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf])) << 6;
+	ecc |= (((~col_parity) >> 2) & 0x3f);
+
+	return ecc & 0xfff;
+}
+
+/**
+ * correct 8 bytes data from 12 bits ECC
+ *
+ * \param[in|out] data input data
+ * \param[in] read_ecc ecc read from storage
+ * \param[in] test_ecc ecc calculated from data
+ * \param[in] errtop top position of error.
+ *
+ * \return:  0 -- no error
+ *			-1 -- can not be corrected
+ *			>0 -- how many bits corrected
+ */
+int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop)
+{
+	u8 d0, d1;			/* deltas */
+	u8 *p = (u8 *)data;
+
+	read_ecc &= 0xfff;
+	test_ecc &= 0xfff;
+
+	d0 = (read_ecc >> 6) ^ (test_ecc >> 6);
+	d1 = (read_ecc & 0x3f) ^ (test_ecc & 0x3f);
+
+	if ((d0 | d1) == 0)
+		return 0;
+	
+	if( ((d0 ^ (d0 >> 1)) & 0x15) == 0x15 &&
+	    ((d1 ^ (d1 >> 1)) & 0x15) == 0x15)
+	{
+		// Single bit (recoverable) error in data
+
+		u8 b;
+		u8 bit;
+		
+		bit = b = 0;		
+		
+		if(d0 & 0x20) b |= 0x04;
+		if(d0 & 0x08) b |= 0x02;
+		if(d0 & 0x02) b |= 0x01;
+
+		if(d1 & 0x20) bit |= 0x04;
+		if(d1 & 0x08) bit |= 0x02;
+		if(d1 & 0x02) bit |= 0x01;
+
+		if (b >= (u8)errtop) return -1;
+		if (bit >= 8) return -1;
+
+		p[b] ^= (1 << bit);
+		
+		return 1;
+	}
+	
+	if ((bits_tbl[d0] + bits_tbl[d1]) == 1) {
+		// error in ecc, no action need		
+		return 1;
+	}
+	
+	// Unrecoverable error
+	return -1;
+}
+

+ 531 - 532
components/dfs/filesystems/uffs/src/uffs/uffs_fd.c

@@ -1,532 +1,531 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_fd.c
- * \brief POSIX like, hight level file operations
- * \author Ricky Zheng, created 8th Jun, 2005
- */
-
-#include <string.h>
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_fd.h"
-#define PFX "fd: "
-
-
-#define FD_OFFSET		3	//!< just make file handler more like POSIX (0, 1, 2 for stdin/stdout/stderr)
-
-#define FD2OBJ(fd)	(((fd) >= FD_OFFSET && (fd) < MAX_DIR_HANDLE + FD_OFFSET) ? \
-						(uffs_Object *)uffs_PoolGetBufByIndex(uffs_GetObjectPool(), (fd) - FD_OFFSET) : NULL )
-
-#define OBJ2FD(obj)		(uffs_PoolGetIndex(uffs_GetObjectPool(), obj) + FD_OFFSET)
-
-#define CHK_OBJ(obj, ret)	do { \
-								if (uffs_PoolVerify(uffs_GetObjectPool(), (obj)) == U_FALSE || \
-										uffs_PoolCheckFreeList(uffs_GetObjectPool(), (obj)) == U_TRUE) { \
-									uffs_set_error(-UEBADF); \
-									return (ret); \
-								} \
-							} while(0)
-
-#define CHK_DIR(dirp, ret)	do { \
-								if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
-										uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
-									uffs_set_error(-UEBADF); \
-									return (ret); \
-								} \
-							} while(0)
-
-#define CHK_DIR_VOID(dirp)	do { \
-								if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
-										uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
-									uffs_set_error(-UEBADF); \
-									return; \
-								} \
-							} while(0)
-
-
-
-static int _dir_pool_data[sizeof(uffs_DIR) * MAX_DIR_HANDLE / sizeof(int)];
-static uffs_Pool _dir_pool;
-static int _uffs_errno = 0;
-
-/**
- * initialise uffs_DIR buffers, called by UFFS internal
- */
-URET uffs_InitDirEntryBuf(void)
-{
-	return uffs_PoolInit(&_dir_pool, _dir_pool_data, sizeof(_dir_pool_data),
-			sizeof(uffs_DIR), MAX_DIR_HANDLE);
-}
-
-/**
- * Release uffs_DIR buffers, called by UFFS internal
- */
-URET uffs_ReleaseDirEntryBuf(void)
-{
-	return uffs_PoolRelease(&_dir_pool);
-}
-
-uffs_Pool * uffs_GetDirEntryBufPool(void)
-{
-	return &_dir_pool;
-}
-
-static uffs_DIR * GetDirEntry(void)
-{
-	uffs_DIR *dirp = (uffs_DIR *) uffs_PoolGet(&_dir_pool);
-
-	if (dirp)
-		memset(dirp, 0, sizeof(uffs_DIR));
-
-	return dirp;
-}
-
-static void PutDirEntry(uffs_DIR *p)
-{
-	uffs_PoolPut(&_dir_pool, p);
-}
-
-
-/** get global errno
- */
-int uffs_get_error(void)
-{
-	return _uffs_errno;
-}
-
-/** set global errno
- */
-int uffs_set_error(int err)
-{
-	return (_uffs_errno = err);
-}
-
-/* POSIX compliant file system APIs */
-
-int uffs_open(const char *name, int oflag, ...)
-{
-	uffs_Object *obj;
-	int ret = 0;
-
-	obj = uffs_GetObject();
-	if (obj == NULL) {
-		uffs_set_error(-UEMFILE);
-		ret = -1;
-	}
-	else {
-		if (uffs_OpenObject(obj, name, oflag) == U_FAIL) {
-			uffs_set_error(-uffs_GetObjectErr(obj));
-			uffs_PutObject(obj);
-			ret = -1;
-		}
-		else {
-			ret = OBJ2FD(obj);
-		}
-	}
-
-	return ret;
-}
-
-int uffs_close(int fd)
-{
-	int ret = 0;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-
-	uffs_ClearObjectErr(obj);
-	if (uffs_CloseObject(obj) == U_FAIL) {
-		uffs_set_error(-uffs_GetObjectErr(obj));
-		ret = -1;
-	}
-	else {
-		uffs_PutObject(obj);
-		ret = 0;
-	}
-
-	return ret;
-}
-
-int uffs_read(int fd, void *data, int len)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = uffs_ReadObject(obj, data, len);
-	uffs_set_error(-uffs_GetObjectErr(obj));
-
-	return ret;
-}
-
-int uffs_write(int fd, void *data, int len)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = uffs_WriteObject(obj, data, len);
-	uffs_set_error(-uffs_GetObjectErr(obj));
-
-	return ret;
-}
-
-long uffs_seek(int fd, long offset, int origin)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = uffs_SeekObject(obj, offset, origin);
-	uffs_set_error(-uffs_GetObjectErr(obj));
-	
-	return ret;
-}
-
-long uffs_tell(int fd)
-{
-	long ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = (long) uffs_GetCurOffset(obj);
-	uffs_set_error(-uffs_GetObjectErr(obj));
-	
-	return ret;
-}
-
-int uffs_eof(int fd)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = uffs_EndOfFile(obj);
-	uffs_set_error(-uffs_GetObjectErr(obj));
-	
-	return ret;
-}
-
-int uffs_flush(int fd)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = (uffs_FlushObject(obj) == U_SUCC) ? 0 : -1;
-	uffs_set_error(-uffs_GetObjectErr(obj));
-	
-	return ret;
-}
-
-int uffs_rename(const char *old_name, const char *new_name)
-{
-	int err = 0;
-	int ret = 0;
-
-	ret = (uffs_RenameObject(old_name, new_name, &err) == U_SUCC) ? 0 : -1;
-	uffs_set_error(-err);
-
-	return ret;
-}
-
-int uffs_remove(const char *name)
-{
-	int err = 0;
-	int ret = 0;
-	struct uffs_stat st;
-
-	if (uffs_stat(name, &st) < 0) {
-		err = UENOENT;
-		ret = -1;
-	}
-	else if (st.st_mode & US_IFDIR) {
-		err = UEISDIR;
-		ret = -1;
-	}
-	else if (uffs_DeleteObject(name, &err) == U_SUCC) {
-		ret = 0;
-	}
-	else {
-		ret = -1;
-	}
-
-	uffs_set_error(-err);
-	return ret;
-}
-
-int uffs_truncate(int fd, long remain)
-{
-	int ret;
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-	uffs_ClearObjectErr(obj);
-	ret = (uffs_TruncateObject(obj, remain) == U_SUCC) ? 0 : -1;
-	uffs_set_error(-uffs_GetObjectErr(obj));
-	
-	return ret;
-}
-
-static int do_stat(uffs_Object *obj, struct uffs_stat *buf)
-{
-	uffs_ObjectInfo info;
-	int ret = 0;
-	int err = 0;
-
-	if (uffs_GetObjectInfo(obj, &info, &err) == U_FAIL) {
-		ret = -1;
-	}
-	else {
-		buf->st_dev = obj->dev->dev_num;
-		buf->st_ino = info.serial;
-		buf->st_nlink = 0;
-		buf->st_uid = 0;
-		buf->st_gid = 0;
-		buf->st_rdev = 0;
-		buf->st_size = info.len;
-		buf->st_blksize = obj->dev->com.pg_data_size;
-		buf->st_blocks = 0;
-		buf->st_atime = info.info.last_modify;
-		buf->st_mtime = info.info.last_modify;
-		buf->st_ctime = info.info.create_time;
-		buf->st_mode = (info.info.attr & FILE_ATTR_DIR ? US_IFDIR : US_IFREG);
-		if (info.info.attr & FILE_ATTR_WRITE)
-			buf->st_mode |= US_IRWXU;
-	}
-
-	uffs_set_error(-err);
-	return ret;
-}
-
-int uffs_stat(const char *name, struct uffs_stat *buf)
-{
-	uffs_Object *obj;
-	int ret = 0;
-	int err = 0;
-	URET result;
-
-	obj = uffs_GetObject();
-	if (obj) {
-		if (*name && name[strlen(name) - 1] == '/') {
-			result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);
-		}
-		else {
-			if ((result = uffs_OpenObject(obj, name, UO_RDONLY)) != U_SUCC)	// try file
-				result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);	// then try dir
-		}
-		if (result == U_SUCC) {
-			ret = do_stat(obj, buf);
-			uffs_CloseObject(obj);
-		}
-		else {
-			err = uffs_GetObjectErr(obj);
-			ret = -1;
-		}
-		uffs_PutObject(obj);
-	}
-	else {
-		err = UENOMEM;
-		ret = -1;
-	}
-
-	uffs_set_error(-err);
-	return ret;
-}
-
-int uffs_lstat(const char *name, struct uffs_stat *buf)
-{
-	return uffs_stat(name, buf);
-}
-
-int uffs_fstat(int fd, struct uffs_stat *buf)
-{
-	uffs_Object *obj = FD2OBJ(fd);
-
-	CHK_OBJ(obj, -1);
-
-	return do_stat(obj, buf);
-}
-
-int uffs_closedir(uffs_DIR *dirp)
-{
-	CHK_DIR(dirp, -1);
-
-	uffs_FindObjectClose(&dirp->f);
-	if (dirp->obj) {
-		uffs_CloseObject(dirp->obj);
-		uffs_PutObject(dirp->obj);
-	}
-	PutDirEntry(dirp);
-
-	return 0;
-}
-
-uffs_DIR * uffs_opendir(const char *path)
-{
-	int err = 0;
-	uffs_DIR *ret = NULL;
-	uffs_DIR *dirp = GetDirEntry();
-
-	if (dirp) {
-		dirp->obj = uffs_GetObject();
-		if (dirp->obj) {
-			if (uffs_OpenObject(dirp->obj, path, UO_RDONLY | UO_DIR) == U_SUCC) {
-				if (uffs_FindObjectOpen(&dirp->f, dirp->obj) == U_SUCC) {
-					ret = dirp;
-					goto ext;
-				}
-				else {
-					uffs_CloseObject(dirp->obj);
-				}
-			}
-			else {
-				err = uffs_GetObjectErr(dirp->obj);
-			}
-			uffs_PutObject(dirp->obj);
-			dirp->obj = NULL;
-		}
-		else {
-			err = UEMFILE;
-		}
-		PutDirEntry(dirp);
-	}
-	else {
-		err = UEMFILE;
-	}
-ext:
-	uffs_set_error(-err);
-	return ret;
-}
-
-struct uffs_dirent * uffs_readdir(uffs_DIR *dirp)
-{
-	struct uffs_dirent *ent;
-
-	CHK_DIR(dirp, NULL);
-
-	if (uffs_FindObjectNext(&dirp->info, &dirp->f) == U_SUCC) {
-		ent = &dirp->dirent;
-		ent->d_ino = dirp->info.serial;
-		ent->d_namelen = dirp->info.info.name_len;
-		memcpy(ent->d_name, dirp->info.info.name, ent->d_namelen);
-		ent->d_name[ent->d_namelen] = 0;
-		ent->d_off = dirp->f.pos;
-		ent->d_reclen = sizeof(struct uffs_dirent);
-		ent->d_type = dirp->info.info.attr;
-
-		return ent;
-	}
-	else
-		return NULL;
-}
-
-void uffs_rewinddir(uffs_DIR *dirp)
-{
-	CHK_DIR_VOID(dirp);
-
-	uffs_FindObjectRewind(&dirp->f);
-}
-
-
-int uffs_mkdir(const char *name, ...)
-{
-	uffs_Object *obj;
-	int ret = 0;
-	int err = 0;
-
-	obj = uffs_GetObject();
-	if (obj) {
-		if (uffs_CreateObject(obj, name, UO_CREATE|UO_DIR) != U_SUCC) {
-			err = obj->err;
-			ret = -1;
-		}
-		else {
-			uffs_CloseObject(obj);
-			ret = 0;
-		}
-		uffs_PutObject(obj);
-	}
-	else {
-		err = UEMFILE;
-		ret = -1;
-	}
-
-	uffs_set_error(-err);
-	return ret;
-}
-
-int uffs_rmdir(const char *name)
-{
-	int err = 0;
-	int ret = 0;
-	struct uffs_stat st;
-
-	if (uffs_stat(name, &st) < 0) {
-		err = UENOENT;
-		ret = -1;
-	}
-	else if ((st.st_mode & US_IFDIR) == 0) {
-		err = UENOTDIR;
-		ret = -1;
-	}
-	else if (uffs_DeleteObject(name, &err) == U_SUCC) {
-		ret = 0;
-	}
-	else {
-		ret = -1;
-	}
-
-	uffs_set_error(-err);
-	return ret;
-}
-
-
-#if 0
-void uffs_seekdir(uffs_DIR *dirp, long loc)
-{
-	return ;
-}
-
-long uffs_telldir(uffs_DIR *dirp)
-{
-	return 0;
-}
-#endif
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+#include <string.h>
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_utils.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_fd.h"
+
+
+#define PFX "fd: "
+
+
+#define FD_OFFSET		3	//!< just make file handler more like POSIX (0, 1, 2 for stdin/stdout/stderr)
+
+#define FD2OBJ(fd)	(((fd) >= FD_OFFSET && (fd) < MAX_DIR_HANDLE + FD_OFFSET) ? \
+						(uffs_Object *)uffs_PoolGetBufByIndex(uffs_GetObjectPool(), (fd) - FD_OFFSET) : NULL )
+
+#define OBJ2FD(obj)		(uffs_PoolGetIndex(uffs_GetObjectPool(), obj) + FD_OFFSET)
+
+#define CHK_OBJ(obj, ret)	do { \
+								if (uffs_PoolVerify(uffs_GetObjectPool(), (obj)) == U_FALSE || \
+										uffs_PoolCheckFreeList(uffs_GetObjectPool(), (obj)) == U_TRUE) { \
+									uffs_set_error(-UEBADF); \
+									return (ret); \
+								} \
+							} while(0)
+
+#define CHK_DIR(dirp, ret)	do { \
+								if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
+										uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
+									uffs_set_error(-UEBADF); \
+									return (ret); \
+								} \
+							} while(0)
+
+#define CHK_DIR_VOID(dirp)	do { \
+								if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
+										uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
+									uffs_set_error(-UEBADF); \
+									return; \
+								} \
+							} while(0)
+
+
+
+static int _dir_pool_data[sizeof(uffs_DIR) * MAX_DIR_HANDLE / sizeof(int)];
+static uffs_Pool _dir_pool;
+static int _uffs_errno = 0;
+
+/**
+ * initialise uffs_DIR buffers, called by UFFS internal
+ */
+int uffs_InitDirEntryBuf(void)
+{
+	return uffs_PoolInit(&_dir_pool, _dir_pool_data, sizeof(_dir_pool_data),
+			sizeof(uffs_DIR), MAX_DIR_HANDLE);
+}
+
+/**
+ * Release uffs_DIR buffers, called by UFFS internal
+ */
+int uffs_ReleaseDirEntryBuf(void)
+{
+	return uffs_PoolRelease(&_dir_pool);
+}
+
+uffs_Pool * uffs_GetDirEntryBufPool(void)
+{
+	return &_dir_pool;
+}
+
+static uffs_DIR * GetDirEntry(void)
+{
+	uffs_DIR *dirp = (uffs_DIR *) uffs_PoolGet(&_dir_pool);
+
+	if(dirp)
+		memset(dirp, 0, sizeof(uffs_DIR));
+
+	return dirp;
+}
+
+static void PutDirEntry(uffs_DIR *p)
+{
+	uffs_PoolPut(&_dir_pool, p);
+}
+
+
+/** get global errno
+ */
+int uffs_get_error(void)
+{
+	return _uffs_errno;
+}
+
+/** set global errno
+ */
+int uffs_set_error(int err)
+{
+	return (_uffs_errno = err);
+}
+
+/* POSIX compliant file system APIs */
+
+int uffs_open(const char *name, int oflag, ...)
+{
+	uffs_Object *obj;
+	int ret = 0;
+
+	obj = uffs_GetObject();
+	if (obj == NULL) {
+		uffs_set_error(-UEMFILE);
+		ret = -1;
+	}
+	else {
+		if (uffs_OpenObject(obj, name, oflag) == U_FAIL) {
+			uffs_set_error(-uffs_GetObjectErr(obj));
+			uffs_PutObject(obj);
+			ret = -1;
+		}
+		else {
+			ret = OBJ2FD(obj);
+		}
+	}
+
+	return ret;
+}
+
+int uffs_close(int fd)
+{
+	int ret = 0;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+
+	uffs_ClearObjectErr(obj);
+	if (uffs_CloseObject(obj) == U_FAIL) {
+		uffs_set_error(-uffs_GetObjectErr(obj));
+		ret = -1;
+	}
+	else {
+		uffs_PutObject(obj);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+int uffs_read(int fd, void *data, int len)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = uffs_ReadObject(obj, data, len);
+	uffs_set_error(-uffs_GetObjectErr(obj));
+
+	return ret;
+}
+
+int uffs_write(int fd, void *data, int len)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = uffs_WriteObject(obj, data, len);
+	uffs_set_error(-uffs_GetObjectErr(obj));
+
+	return ret;
+}
+
+long uffs_seek(int fd, long offset, int origin)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = uffs_SeekObject(obj, offset, origin);
+	uffs_set_error(-uffs_GetObjectErr(obj));
+	
+	return ret;
+}
+
+long uffs_tell(int fd)
+{
+	long ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = (long) uffs_GetCurOffset(obj);
+	uffs_set_error(-uffs_GetObjectErr(obj));
+	
+	return ret;
+}
+
+int uffs_eof(int fd)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = uffs_EndOfFile(obj);
+	uffs_set_error(-uffs_GetObjectErr(obj));
+	
+	return ret;
+}
+
+int uffs_flush(int fd)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = (uffs_FlushObject(obj) == U_SUCC) ? 0 : -1;
+	uffs_set_error(-uffs_GetObjectErr(obj));
+	
+	return ret;
+}
+
+int uffs_rename(const char *old_name, const char *new_name)
+{
+	int err = 0;
+	int ret = 0;
+
+	ret = (uffs_RenameObject(old_name, new_name, &err) == U_SUCC) ? 0 : -1;
+	uffs_set_error(-err);
+
+	return ret;
+}
+
+int uffs_remove(const char *name)
+{
+	int err = 0;
+	int ret = 0;
+	struct uffs_stat st;
+
+	if (uffs_stat(name, &st) < 0) {
+		err = UENOENT;
+		ret = -1;
+	}
+	else if (st.st_mode & US_IFDIR) {
+		err = UEISDIR;
+		ret = -1;
+	}
+	else if (uffs_DeleteObject(name, &err) == U_SUCC) {
+		ret = 0;
+	}
+	else {
+		ret = -1;
+	}
+
+	uffs_set_error(-err);
+	return ret;
+}
+
+
+int uffs_truncate(int fd, long remain)
+{
+	int ret;
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+	uffs_ClearObjectErr(obj);
+	ret = (uffs_TruncateObject(obj, remain) == U_SUCC) ? 0 : -1;
+	uffs_set_error(-uffs_GetObjectErr(obj));
+	
+	return ret;
+}
+
+static int do_stat(uffs_Object *obj, struct uffs_stat *buf)
+{
+	uffs_ObjectInfo info;
+	int ret = 0;
+	int err = 0;
+
+	if (uffs_GetObjectInfo(obj, &info, &err) == U_FAIL) {
+		ret = -1;
+	}
+	else {
+		buf->st_dev = obj->dev->dev_num;
+		buf->st_ino = info.serial;
+		buf->st_nlink = 0;
+		buf->st_uid = 0;
+		buf->st_gid = 0;
+		buf->st_rdev = 0;
+		buf->st_size = info.len;
+		buf->st_blksize = obj->dev->com.pg_data_size;
+		buf->st_blocks = 0;
+		buf->st_atime = info.info.last_modify;
+		buf->st_mtime = info.info.last_modify;
+		buf->st_ctime = info.info.create_time;
+		buf->st_mode = (info.info.attr & FILE_ATTR_DIR ? US_IFDIR : US_IFREG);
+		if (info.info.attr & FILE_ATTR_WRITE)
+			buf->st_mode |= US_IRWXU;
+	}
+
+	uffs_set_error(-err);
+	return ret;
+}
+
+int uffs_stat(const char *name, struct uffs_stat *buf)
+{
+	uffs_Object *obj;
+	int ret = 0;
+	int err = 0;
+	URET result;
+
+	obj = uffs_GetObject();
+	if (obj) {
+		if (*name && name[strlen(name) - 1] == '/') {
+			result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);
+		}
+		else {
+			if ((result = uffs_OpenObject(obj, name, UO_RDONLY)) != U_SUCC)	// try file
+				result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);	// then try dir
+		}
+		if (result == U_SUCC) {
+			ret = do_stat(obj, buf);
+			uffs_CloseObject(obj);
+		}
+		else {
+			err = uffs_GetObjectErr(obj);
+			ret = -1;
+		}
+		uffs_PutObject(obj);
+	}
+	else {
+		err = UENOMEM;
+		ret = -1;
+	}
+
+	uffs_set_error(-err);
+	return ret;
+}
+
+int uffs_lstat(const char *name, struct uffs_stat *buf)
+{
+	return uffs_stat(name, buf);
+}
+
+int uffs_fstat(int fd, struct uffs_stat *buf)
+{
+	uffs_Object *obj = FD2OBJ(fd);
+
+	CHK_OBJ(obj, -1);
+
+	return do_stat(obj, buf);
+}
+
+int uffs_closedir(uffs_DIR *dirp)
+{
+	CHK_DIR(dirp, -1);
+
+	uffs_FindObjectClose(&dirp->f);
+	if (dirp->obj) {
+		uffs_CloseObject(dirp->obj);
+		uffs_PutObject(dirp->obj);
+	}
+	PutDirEntry(dirp);
+
+	return 0;
+}
+
+uffs_DIR * uffs_opendir(const char *path)
+{
+	int err = 0;
+	uffs_DIR *ret = NULL;
+	uffs_DIR *dirp = GetDirEntry();
+
+	if (dirp) {
+		dirp->obj = uffs_GetObject();
+		if (dirp->obj) {
+			if (uffs_OpenObject(dirp->obj, path, UO_RDONLY | UO_DIR) == U_SUCC) {
+				if (uffs_FindObjectOpen(&dirp->f, dirp->obj) == U_SUCC) {
+					ret = dirp;
+					goto ext;
+				}
+				else {
+					uffs_CloseObject(dirp->obj);
+				}
+			}
+			else {
+				err = uffs_GetObjectErr(dirp->obj);
+			}
+			uffs_PutObject(dirp->obj);
+			dirp->obj = NULL;
+		}
+		else {
+			err = UEMFILE;
+		}
+		PutDirEntry(dirp);
+	}
+	else {
+		err = UEMFILE;
+	}
+ext:
+	uffs_set_error(-err);
+	return ret;
+}
+
+struct uffs_dirent* uffs_readdir(uffs_DIR *dirp)
+{
+	struct uffs_dirent *ent = &dirp->dirent;
+
+	//CHK_DIR(dirp, NULL);
+	if(dirp == NULL)
+		return NULL;
+	
+	if(uffs_FindObjectNext(&dirp->info, &dirp->f) == RT_EOK) 
+	{
+		ent->d_ino = dirp->info.serial;
+		ent->d_namelen = dirp->info.info.name_len;
+		memcpy(ent->d_name, dirp->info.info.name, ent->d_namelen);
+		ent->d_name[ent->d_namelen] = 0;
+		ent->d_off = dirp->f.pos;
+		ent->d_reclen = sizeof(struct uffs_dirent);
+		ent->d_type = dirp->info.info.attr;
+
+		return ent;
+	}
+	else
+		return NULL;
+}
+
+void uffs_rewinddir(uffs_DIR *dirp)
+{
+	CHK_DIR_VOID(dirp);
+
+	uffs_FindObjectRewind(&dirp->f);	//fi(=)find info
+}
+
+/*
+ * 函数功能: 创建一个文件夹
+ * 输入参数: 文件夹名称,参数
+ * 返回参数: 
+ */
+int uffs_mkdir(const char *name, ...)
+{
+	uffs_Object *obj;
+	int ret = 0;
+	int err = 0;
+
+	obj = uffs_GetObject();
+	if (obj) {
+		if (uffs_CreateObject(obj, name, UO_CREATE|UO_DIR) != U_SUCC) {
+			err = obj->err;
+			ret = -1;
+		}
+		else {
+			uffs_CloseObject(obj);
+			ret = 0;
+		}
+		uffs_PutObject(obj);
+	}
+	else {
+		err = UEMFILE;
+		ret = -1;
+	}
+
+	uffs_set_error(-err);
+	return ret;
+}
+
+/*
+ * 函数功能: 移除一个文件夹
+ * 输入参数: 文件夹名称
+ * 返回参数: 
+ */
+int uffs_rmdir(const char *name)
+{
+	int err = 0;
+	int ret = 0;
+	struct uffs_stat st;
+
+	if (uffs_stat(name, &st) < 0) {
+		err = UENOENT;
+		ret = -1;
+	}
+	else if ((st.st_mode & US_IFDIR) == 0) {
+		err = UENOTDIR;
+		ret = -1;
+	}
+	else if (uffs_DeleteObject(name, &err) == U_SUCC) {
+		ret = 0;
+	}
+	else {
+		ret = -1;
+	}
+
+	uffs_set_error(-err);
+	return ret;
+}
+

+ 372 - 360
components/dfs/filesystems/uffs/src/uffs/uffs_find.c

@@ -1,360 +1,372 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_find.c
- * \brief find objects under dir
- * \author Ricky Zheng, created 13th July, 2009
- */
-
-#include <string.h> 
-#include <stdio.h>
-#include "uffs/uffs_find.h"
-
-#define TPOOL(dev) &((dev)->mem.tree_pool)
-
-static void ResetFindInfo(uffs_FindInfo *f)
-{
-	f->hash = 0;
-	f->work = NULL;
-	f->step = 0;
-	f->pos = 0;
-}
-
-static URET _LoadObjectInfo(uffs_Device *dev, TreeNode *node, uffs_ObjectInfo *info, int type, int *err)
-{
-	uffs_Buf *buf;
-
-	buf = uffs_BufGetEx(dev, (u8)type, node, 0);
-
-	if (buf == NULL) {
-		if (err)
-			*err = UENOMEM;
-		return U_FAIL;
-	}
-
-	memcpy(&(info->info), buf->data, sizeof(uffs_FileInfo));
-
-	if (type == UFFS_TYPE_DIR) {
-		info->len = 0;
-		info->serial = node->u.dir.serial;
-	}
-	else {
-		info->len = node->u.file.len;
-		info->serial = node->u.file.serial;
-	}
-
-	uffs_BufPut(dev, buf);
-
-	return U_SUCC;
-}
-
-/**
- * get object information
- *
- * \param[in] obj the object to be revealed
- * \param[out] info object information will be loaded to info
- * \param[out] err return error code if failed
- *
- * \return U_SUCC or U_FAIL
- *
- * \node the obj should be openned before call this function.
- */
-URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err)
-{
-	uffs_Device *dev = obj->dev;
-	URET ret = U_FAIL;
-
-	uffs_DeviceLock(dev);
-
-	if (obj && dev && info) {
-		ret = _LoadObjectInfo(dev, obj->node, info, obj->type, err);
-	}
-	else {
-		if (err)
-			*err = UEINVAL;
-	}
-
-	uffs_DeviceUnLock(dev);
-
-	return ret;
-}
-
-
-/**
- * Open a FindInfo for finding objects under dir
- *
- * \param[out] f uffs_FindInfo structure
- * \param[in] dir an openned dir object (openned by uffs_OpenObject() ). 
- *
- * \return U_SUCC if success, U_FAIL if invalid param or the dir
- *			is not been openned.
- */
-URET uffs_FindObjectOpen(uffs_FindInfo *f, uffs_Object *dir)
-{
-	if (f == NULL || dir == NULL || dir->dev == NULL || dir->open_succ != U_TRUE)
-		return U_FAIL;
-
-	f->dev = dir->dev;
-	f->serial = dir->serial;
-	ResetFindInfo(f);
-
-	return U_SUCC;
-}
-
-/**
- * Open a FindInfo for finding objects under dir
- *
- * \param[out] f uffs_FindInfo structure
- * \param[in] dev uffs device
- * \param[in] dir serial number of the dir to be searched
- *
- * \return U_SUCC if success, U_FAIL if invalid param or the dir
- *			serial number is not valid.
- */
-URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir)
-{
-	TreeNode *node;
-
-	if (f == NULL || dev == NULL)
-		return U_FAIL;
-
-	node = uffs_TreeFindDirNode(dev, dir);
-
-	if (node == NULL)
-		return U_FAIL;
-
-	f->serial = dir;
-	f->dev = dev;
-	ResetFindInfo(f);
-
-	return U_SUCC;
-}
-
-
-static URET do_FindObject(uffs_FindInfo *f, uffs_ObjectInfo *info, u16 x)
-{
-	URET ret = U_SUCC;
-	TreeNode *node;
-	uffs_Device *dev = f->dev;
-
-	if (f->step == 0) { //!< working on dirs
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.dir.parent == f->serial) {
-				f->work = node;
-				f->pos++;
-				if (info)
-					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
-				goto ext;
-			}
-			x = node->hash_next;
-		}
-
-		f->hash++; //come to next hash entry
-
-		for (; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) {
-			x = dev->tree.dir_entry[f->hash];
-			while (x != EMPTY_NODE) {
-				node = FROM_IDX(x, TPOOL(dev));
-				if (node->u.dir.parent == f->serial) {
-					f->work = node;
-					f->pos++;
-					if (info)
-						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
-					goto ext;
-				}
-				x = node->hash_next;
-			}
-		}
-
-		//no subdirs, then lookup files ..
-		f->step++;
-		f->hash = 0;
-		x = EMPTY_NODE;
-	}
-
-	if (f->step == 1) {
-
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.file.parent == f->serial) {
-				f->work = node;
-				f->pos++;
-				if (info)
-					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
-				goto ext;
-			}
-			x = node->hash_next;
-		}
-
-		f->hash++; //come to next hash entry
-
-		for (; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) {
-			x = dev->tree.file_entry[f->hash];
-			while (x != EMPTY_NODE) {
-				node = FROM_IDX(x, TPOOL(dev));
-				if (node->u.file.parent == f->serial) {
-					f->work = node;
-					f->pos++;
-					if (info) 
-						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
-					goto ext;
-				}
-				x = node->hash_next;
-			}
-		}
-
-		//no any files, stopped.
-		f->step++;
-	}
-
-	ret = U_FAIL;
-ext:
-
-	return ret;
-
-}
-
-
-/**
- * Find the first object
- *
- * \param[out] info the object information will be filled to info.
- *				if info is NULL, then skip this object.
- * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
- *
- * \return U_SUCC if an object is found, U_FAIL if no object is found.
- */
-URET uffs_FindObjectFirst(uffs_ObjectInfo * info, uffs_FindInfo * f)
-{
-	uffs_Device *dev = f->dev;
-	URET ret = U_SUCC;
-
-	uffs_DeviceLock(dev);
-	ResetFindInfo(f);
-	ret = do_FindObject(f, info, dev->tree.dir_entry[0]);
-	uffs_DeviceUnLock(dev);
-
-	return ret;
-}
-
-/**
- * Find the next object.
- *
- * \param[out] info the object information will be filled to info.
- *				if info is NULL, then skip this object.
- * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
- *
- * \return U_SUCC if an object is found, U_FAIL if no object is found.
- *
- * \note uffs_FindObjectFirst() should be called before uffs_FindObjectNext().
- */
-URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo * f)
-{
-	uffs_Device *dev = f->dev;
-	URET ret = U_SUCC;
-
-	if (f->dev == NULL || f->step > 1) 
-		return U_FAIL;
-
-	if (f->work == NULL)
-		return uffs_FindObjectFirst(info, f);
-
-	uffs_DeviceLock(dev);
-	ret = do_FindObject(f, info, f->work->hash_next);
-	uffs_DeviceUnLock(dev);
-
-	return ret;
-}
-
-/**
- * Rewind a find object process.
- *
- * \note After rewind, you can call uffs_FindObjectFirst() to start find object process.
- */
-URET uffs_FindObjectRewind(uffs_FindInfo *f)
-{
-	if (f == NULL)
-		return U_FAIL;
-
-	ResetFindInfo(f);
-
-	return U_SUCC;
-}
-
-/**
- * Close Find Object.
- *
- * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
- *
- * \return U_SUCC if success, U_FAIL if invalid param.
- */
-URET uffs_FindObjectClose(uffs_FindInfo * f)
-{
-	if (f == NULL)
-		return U_FAIL;
-
-	f->dev = NULL;
-	ResetFindInfo(f);
-
-	return U_SUCC;
-}
-
-/**
- * Count objects
- *
- * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
- *
- * \return object counts
- * \note after call this function, you need to call uffs_FindObjectRewind() to start finding process.
- */
-int uffs_FindObjectCount(uffs_FindInfo *f)
-{
-	if (uffs_FindObjectFirst(NULL, f) == U_SUCC) {
-		while (uffs_FindObjectNext(NULL, f) == U_SUCC) { };
-	}
-	return f->pos;
-}
-
-/**
- * Return current finding position
- *
- * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
- *
- * \return current finding position
- */
-int uffs_FindObjectTell(uffs_FindInfo *f)
-{
-	return f->pos;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_find.c
+ * \brief find objects under dir
+ * \author Ricky Zheng, created 13th July, 2009
+ */
+
+#include <string.h> 
+#include <stdio.h>
+#include "uffs/uffs_find.h"
+
+#define TPOOL(dev) &((dev)->mem.tree_pool)
+
+static void ResetFindInfo(uffs_FindInfo *f)
+{
+	f->hash = 0;
+	f->work = NULL;
+	f->step = 0;
+	f->pos = 0;
+}
+
+static URET _LoadObjectInfo(uffs_Device *dev, TreeNode *node, uffs_ObjectInfo *info, int type, int *err)
+{
+	uffs_Buf *buf;
+
+	buf = uffs_BufGetEx(dev, (u8)type, node, 0);
+
+	if (buf == NULL) {
+		if (err)
+			*err = UENOMEM;
+		return U_FAIL;
+	}
+
+	memcpy(&(info->info), buf->data, sizeof(uffs_FileInfo));
+
+	if (type == UFFS_TYPE_DIR) {
+		info->len = 0;
+		info->serial = node->u.dir.serial;
+	}
+	else {
+		info->len = node->u.file.len;
+		info->serial = node->u.file.serial;
+	}
+
+	uffs_BufPut(dev, buf);
+
+	return U_SUCC;
+}
+
+/**
+ * get object information
+ *
+ * \param[in] obj the object to be revealed
+ * \param[out] info object information will be loaded to info
+ * \param[out] err return error code if failed
+ *
+ * \return U_SUCC or U_FAIL
+ *
+ * \node the obj should be openned before call this function.
+ */
+URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err)
+{
+	uffs_Device *dev = obj->dev;
+	URET ret = U_FAIL;
+
+	uffs_DeviceLock(dev);
+
+	if (obj && dev && info) {
+		ret = _LoadObjectInfo(dev, obj->node, info, obj->type, err);
+	}
+	else {
+		if (err)
+			*err = UEINVAL;
+	}
+
+	uffs_DeviceUnLock(dev);
+
+	return ret;
+}
+
+
+/**
+ * Open a FindInfo for finding objects under dir
+ *
+ * \param[out] f uffs_FindInfo structure
+ * \param[in] dir an openned dir object (openned by uffs_OpenObject() ). 
+ *
+ * \return U_SUCC if success, U_FAIL if invalid param or the dir
+ *			is not been openned.
+ */
+URET uffs_FindObjectOpen(uffs_FindInfo *f, uffs_Object *dir)
+{
+	if (f == NULL || dir == NULL || dir->dev == NULL || dir->open_succ != U_TRUE)
+		return U_FAIL;
+
+	f->dev = dir->dev;
+	f->serial = dir->serial;
+	ResetFindInfo(f);
+
+	return U_SUCC;
+}
+
+/**
+ * Open a FindInfo for finding objects under dir
+ *
+ * \param[out] f uffs_FindInfo structure
+ * \param[in] dev uffs device
+ * \param[in] dir serial number of the dir to be searched
+ *
+ * \return U_SUCC if success, U_FAIL if invalid param or the dir
+ *			serial number is not valid.
+ */
+URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir)
+{
+	TreeNode *node;
+
+	if (f == NULL || dev == NULL)
+		return U_FAIL;
+
+	node = uffs_TreeFindDirNode(dev, dir);
+
+	if (node == NULL)
+		return U_FAIL;
+
+	f->serial = dir;
+	f->dev = dev;
+	ResetFindInfo(f);
+
+	return U_SUCC;
+}
+
+
+static URET do_FindObject(uffs_FindInfo *f, uffs_ObjectInfo *info, u16 x)
+{
+	URET ret = U_SUCC;
+	TreeNode *node;
+	uffs_Device *dev = f->dev;
+
+	if (f->step == 0) 
+	{ //!< working on dirs
+		while (x != EMPTY_NODE) 
+		{
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.dir.parent == f->serial) 
+			{
+				f->work = node;
+				f->pos++;
+				if (info)
+					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
+				goto ext;
+			}
+			x = node->hash_next;
+		}
+
+		f->hash++; //come to next hash entry
+
+		for (; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) 
+		{
+			x = dev->tree.dir_entry[f->hash];
+			while (x != EMPTY_NODE) 
+			{
+				node = FROM_IDX(x, TPOOL(dev));
+				if (node->u.dir.parent == f->serial) 
+				{
+					f->work = node;
+					f->pos++;
+					if (info)
+						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
+					goto ext;
+				}
+				x = node->hash_next;
+			}
+		}
+
+		//no subdirs, then lookup files ..
+		f->step++;
+		f->hash = 0;
+		x = EMPTY_NODE;
+	}
+
+	if (f->step == 1) 
+	{
+
+		while (x != EMPTY_NODE) 
+		{
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.file.parent == f->serial) 
+			{
+				f->work = node;
+				f->pos++;
+				if (info)
+					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
+				goto ext;
+			}
+			x = node->hash_next;
+		}
+
+		f->hash++; //come to next hash entry
+
+		for (; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) 
+		{
+			x = dev->tree.file_entry[f->hash];
+			while (x != EMPTY_NODE) 
+			{
+				node = FROM_IDX(x, TPOOL(dev));
+				if (node->u.file.parent == f->serial) 
+				{
+					f->work = node;
+					f->pos++;
+					if (info) 
+						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
+					goto ext;
+				}
+				x = node->hash_next;
+			}
+		}
+
+		//no any files, stopped.
+		f->step++;
+	}
+
+	ret = U_FAIL;
+ext:
+
+	return ret;
+
+}
+
+
+/**
+ * Find the first object
+ *
+ * \param[out] info the object information will be filled to info.
+ *				if info is NULL, then skip this object.
+ * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
+ *
+ * \return U_SUCC if an object is found, U_FAIL if no object is found.
+ */
+URET uffs_FindObjectFirst(uffs_ObjectInfo * info, uffs_FindInfo * f)
+{
+	uffs_Device *dev = f->dev;
+	URET ret = U_SUCC;
+
+	uffs_DeviceLock(dev);
+	ResetFindInfo(f);
+	ret = do_FindObject(f, info, dev->tree.dir_entry[0]);
+	uffs_DeviceUnLock(dev);
+
+	return ret;
+}
+
+/**
+ * Find the next object.
+ *
+ * \param[out] info the object information will be filled to info.
+ *				if info is NULL, then skip this object.
+ * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
+ *
+ * \return U_SUCC if an object is found, U_FAIL if no object is found.
+ *
+ * \note uffs_FindObjectFirst() should be called before uffs_FindObjectNext().
+ */
+URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo * f)
+{
+	uffs_Device *dev = f->dev;
+	URET ret = U_SUCC;
+
+	if (f->dev == NULL || f->step > 1) 
+		return U_FAIL;
+
+	if (f->work == NULL)
+		return uffs_FindObjectFirst(info, f);
+
+	uffs_DeviceLock(dev);
+	ret = do_FindObject(f, info, f->work->hash_next);
+	uffs_DeviceUnLock(dev);
+
+	return ret;
+}
+
+/**
+ * Rewind a find object process.
+ *
+ * \note After rewind, you can call uffs_FindObjectFirst() to start find object process.
+ */
+URET uffs_FindObjectRewind(uffs_FindInfo *f)
+{
+	if (f == NULL)
+		return U_FAIL;
+
+	ResetFindInfo(f);
+
+	return U_SUCC;
+}
+
+/**
+ * Close Find Object.
+ *
+ * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
+ *
+ * \return U_SUCC if success, U_FAIL if invalid param.
+ */
+URET uffs_FindObjectClose(uffs_FindInfo * f)
+{
+	if (f == NULL)
+		return U_FAIL;
+
+	f->dev = NULL;
+	ResetFindInfo(f);
+
+	return U_SUCC;
+}
+
+/**
+ * Count objects
+ *
+ * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
+ *
+ * \return object counts
+ * \note after call this function, you need to call uffs_FindObjectRewind() to start finding process.
+ */
+int uffs_FindObjectCount(uffs_FindInfo *f)
+{
+	if (uffs_FindObjectFirst(NULL, f) == U_SUCC) {
+		while (uffs_FindObjectNext(NULL, f) == U_SUCC) { };
+	}
+	return f->pos;
+}
+
+/**
+ * Return current finding position
+ *
+ * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
+ *
+ * \return current finding position
+ */
+int uffs_FindObjectTell(uffs_FindInfo *f)
+{
+	return f->pos;
+}
+

+ 674 - 674
components/dfs/filesystems/uffs/src/uffs/uffs_flash.c

@@ -1,674 +1,674 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_flash.c
- * \brief UFFS flash interface
- * \author Ricky Zheng, created 17th July, 2009
- */
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_ecc.h"
-#include "uffs/uffs_flash.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_badblock.h"
-#include <string.h>
-
-#define PFX "Flash: "
-
-#define SPOOL(dev) &((dev)->mem.spare_pool)
-#define HEADER(buf) ((struct uffs_MiniHeaderSt *)(buf)->header)
-
-#define ECC_SIZE(dev) (3 * (dev)->attr->page_data_size / 256)
-#define TAG_STORE_SIZE	(sizeof(struct uffs_TagStoreSt))
-
-
-static void TagMakeEcc(struct uffs_TagStoreSt *ts)
-{
-	ts->tag_ecc = 0xFFF;
-	ts->tag_ecc = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
-}
-
-static int TagEccCorrect(struct uffs_TagStoreSt *ts)
-{
-	u16 ecc_store, ecc_read;
-	int ret;
-
-	ecc_store = ts->tag_ecc;
-	ts->tag_ecc = 0xFFF;
-	ecc_read = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
-	ret = uffs_EccCorrect8(ts, ecc_read, ecc_store, sizeof(struct uffs_TagStoreSt));
-	ts->tag_ecc = ecc_store;	// restore tag ecc
-
-	return ret;
-
-}
-
-/** setup UFFS spare data & ecc layout */
-static void InitSpareLayout(uffs_Device *dev)
-{
-	u8 s; // status byte offset
-	u8 *p;
-
-	s = dev->attr->block_status_offs;
-
-	if (s < TAG_STORE_SIZE) {	/* status byte is within 0 ~ TAG_STORE_SIZE-1 */
-
-		/* spare data layout */
-		p = dev->attr->_uffs_data_layout;
-		if (s > 0) {
-			*p++ = 0;
-			*p++ = s;
-		}
-		*p++ = s + 1;
-		*p++ = TAG_STORE_SIZE - s;
-		*p++ = 0xFF;
-		*p++ = 0;
-
-		/* spare ecc layout */
-		p = dev->attr->_uffs_ecc_layout;
-		*p++ = TAG_STORE_SIZE + 1;
-		*p++ = ECC_SIZE(dev);
-		*p++ = 0xFF;
-		*p++ = 0;
-	}
-	else {	/* status byte > TAG_STORE_SIZE-1 */
-
-		/* spare data layout */
-		p = dev->attr->_uffs_data_layout;
-		*p++ = 0;
-		*p++ = TAG_STORE_SIZE;
-		*p++ = 0xFF;
-		*p++ = 0;
-
-		/* spare ecc layout */
-		p = dev->attr->_uffs_ecc_layout;
-		if (s < TAG_STORE_SIZE + ECC_SIZE(dev)) {
-			if (s > TAG_STORE_SIZE) {
-				*p++ = TAG_STORE_SIZE;
-				*p++ = s - TAG_STORE_SIZE;
-			}
-			*p++ = s + 1;
-			*p++ = TAG_STORE_SIZE + ECC_SIZE(dev) - s;
-		}
-		else {
-			*p++ = TAG_STORE_SIZE;
-			*p++ = ECC_SIZE(dev);
-		}
-		*p++ = 0xFF;
-		*p++ = 0;
-	}
-
-	dev->attr->data_layout = dev->attr->_uffs_data_layout;
-	dev->attr->ecc_layout = dev->attr->_uffs_ecc_layout;
-}
-
-static int CalculateSpareDataSize(uffs_Device *dev)
-{
-	const u8 *p;
-	int ecc_last = 0, tag_last = 0;
-	int ecc_size, tag_size;
-	int n;
-
-	ecc_size = ECC_SIZE(dev);
-	
-	p = dev->attr->ecc_layout;
-	if (p) {
-		while (*p != 0xFF && ecc_size > 0) {
-			n = (p[1] > ecc_size ? ecc_size : p[1]);
-			ecc_last = p[0] + n;
-			ecc_size -= n;
-			p += 2;
-		}
-	}
-
-	tag_size = TAG_STORE_SIZE;
-	p = dev->attr->data_layout;
-	if (p) {
-		while (*p != 0xFF && tag_size > 0) {
-			n = (p[1] > tag_size ? tag_size : p[1]);
-			tag_last = p[0] + n;
-			tag_size -= n;
-			p += 2;
-		}
-	}
-
-	n = (ecc_last > tag_last ? ecc_last : tag_last);
-	n = (n > dev->attr->block_status_offs + 1 ? n : dev->attr->block_status_offs + 1);
-
-	return n;
-}
-
-
-/**
- * Initialize UFFS flash interface
- */
-URET uffs_FlashInterfaceInit(uffs_Device *dev)
-{
-	struct uffs_StorageAttrSt *attr = dev->attr;
-	uffs_Pool *pool = SPOOL(dev);
-
-	if (!dev->ops->IsBadBlock && !dev->ops->ReadPageSpare) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'IsBadBlock' or 'ReadPageSpare' function!");
-		return U_FAIL;
-	}
-
-	if (!dev->ops->MarkBadBlock && !dev->ops->WritePageSpare && !dev->ops->WriteFullPage) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'MarkBadBlock' or 'WritePageSpare' or 'WriteFullPage' function!");
-		return U_FAIL;
-	}
-
-	if (dev->mem.spare_pool_size == 0) {
-		if (dev->mem.malloc) {
-			dev->mem.spare_pool_buf = dev->mem.malloc(dev, UFFS_SPARE_BUFFER_SIZE);
-			if (dev->mem.spare_pool_buf)
-				dev->mem.spare_pool_size = UFFS_SPARE_BUFFER_SIZE;
-		}
-	}
-
-	if (UFFS_SPARE_BUFFER_SIZE > dev->mem.spare_pool_size) {
-		uffs_Perror(UFFS_ERR_DEAD, "Spare buffer require %d but only %d available.", UFFS_SPARE_BUFFER_SIZE, dev->mem.spare_pool_size);
-		memset(pool, 0, sizeof(uffs_Pool));
-		return U_FAIL;
-	}
-
-	uffs_Perror(UFFS_ERR_NOISY, "alloc spare buffers %d bytes.", UFFS_SPARE_BUFFER_SIZE);
-	uffs_PoolInit(pool, dev->mem.spare_pool_buf, dev->mem.spare_pool_size, UFFS_MAX_SPARE_SIZE, MAX_SPARE_BUFFERS);
-
-	if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
-		/* sanity check */
-		if ((dev->attr->data_layout && !dev->attr->ecc_layout) ||
-			(!dev->attr->data_layout && dev->attr->ecc_layout)) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Please setup data_layout and ecc_layout, or leave them all NULL !");
-			return U_FAIL;
-		}
-
-		if (!attr->data_layout && !attr->ecc_layout)
-			InitSpareLayout(dev);
-	}
-
-	dev->mem.spare_data_size = CalculateSpareDataSize(dev);
-
-	return U_SUCC;
-}
-
-/**
- * Release UFFS flash interface
- */
-URET uffs_FlashInterfaceRelease(uffs_Device *dev)
-{
-	uffs_Pool *pool;
-	
-	pool = SPOOL(dev);
-	if (pool->mem && dev->mem.free) {
-		dev->mem.free(dev, pool->mem);
-		pool->mem = NULL;
-		dev->mem.spare_pool_size = 0;
-	}
-	uffs_PoolRelease(pool);
-	memset(pool, 0, sizeof(uffs_Pool));
-
-	return U_SUCC;
-}
-
-/**
- * unload spare to tag and ecc.
- */
-static void UnloadSpare(uffs_Device *dev, const u8 *spare, uffs_Tags *tag, u8 *ecc)
-{
-	u8 *p_tag = (u8 *)&tag->s;
-	int tag_size = TAG_STORE_SIZE;
-	int ecc_size = ECC_SIZE(dev);
-	int n;
-	const u8 *p;
-
-	// unload ecc
-	p = dev->attr->ecc_layout;
-	if (p && ecc) {
-		while (*p != 0xFF && ecc_size > 0) {
-			n = (p[1] > ecc_size ? ecc_size : p[1]);
-			memcpy(ecc, spare + p[0], n);
-			ecc_size -= n;
-			ecc += n;
-			p += 2;
-		}
-	}
-
-	// unload tag
-	if (tag) {
-		p = dev->attr->data_layout;
-		while (*p != 0xFF && tag_size > 0) {
-			n = (p[1] > tag_size ? tag_size : p[1]);
-			memcpy(p_tag, spare + p[0], n);
-			tag_size -= n;
-			p_tag += n;
-			p += 2;
-		}
-
-		tag->block_status = spare[dev->attr->block_status_offs];
-	}
-}
-
-/**
- * Read tag and ecc from page spare
- *
- * \param[in] dev uffs device
- * \param[in] block flash block num
- * \param[in] page flash page num
- * \param[out] tag tag to be filled
- * \param[out] ecc ecc to be filled
- *
- * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
- *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
- *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
- *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
-*/
-int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc)
-{
-	uffs_FlashOps *ops = dev->ops;
-	struct uffs_StorageAttrSt *attr = dev->attr;
-	u8 * spare_buf;
-	int ret = UFFS_FLASH_UNKNOWN_ERR;
-	UBOOL is_bad = U_FALSE;
-
-	spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev));
-	if (spare_buf == NULL)
-		goto ext;
-
-	if (ops->ReadPageSpareWithLayout)
-		ret = ops->ReadPageSpareWithLayout(dev, block, page, (u8 *)&tag->s, tag ? TAG_STORE_SIZE : 0, ecc);
-	else
-		ret = ops->ReadPageSpare(dev, block, page, spare_buf, 0, dev->mem.spare_data_size);
-
-
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		is_bad = U_TRUE;
-
-	if (!ops->ReadPageSpareWithLayout)
-		UnloadSpare(dev, spare_buf, tag, ecc);
-
-	// copy some raw data
-	if (tag) {
-		tag->_dirty = tag->s.dirty;
-		tag->_valid = tag->s.valid;
-	}
-
-	if (UFFS_FLASH_HAVE_ERR(ret))
-		goto ext;
-
-	if (tag) {
-		if (tag->_valid == 1) //it's not a valid page ? don't need go further
-			goto ext;
-
-		// do tag ecc correction
-		if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
-			ret = TagEccCorrect(&tag->s);
-			ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
-					(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
-
-			if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-				is_bad = U_TRUE;
-
-			if (UFFS_FLASH_HAVE_ERR(ret))
-				goto ext;
-		}
-	}
-
-ext:
-	if (is_bad) {
-		uffs_BadBlockAdd(dev, block);
-		uffs_Perror(UFFS_ERR_NORMAL, "A new bad block (%d) is detected.", block);
-	}
-
-	if (spare_buf)
-		uffs_PoolPut(SPOOL(dev), spare_buf);
-
-	return ret;
-}
-
-/**
- * Read page data to page buf and calculate ecc.
- * \param[in] dev uffs device
- * \param[in] block flash block num
- * \param[in] page flash page num of the block
- * \param[out] buf holding the read out data
- *
- * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
- *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
- *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
- *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
- */
-int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf)
-{
-	uffs_FlashOps *ops = dev->ops;
-	int size = dev->com.pg_size;
-	u8 ecc_buf[MAX_ECC_SIZE];
-	u8 ecc_store[MAX_ECC_SIZE];
-	UBOOL is_bad = U_FALSE;
-
-	int ret;
-
-	// if ecc_opt is UFFS_ECC_HW, flash driver return ecc,
-	// if ecc_opt is UFFS_ECC_HW_AUTO, flash driver should do ecc correction.
-	ret = ops->ReadPageData(dev, block, page, buf->header, size, ecc_buf);
-	
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		is_bad = U_TRUE;
-
-	if (UFFS_FLASH_HAVE_ERR(ret))
-		goto ext;
-
-	if (dev->attr->ecc_opt == UFFS_ECC_SOFT || dev->attr->ecc_opt == UFFS_ECC_HW) {
-	  
-		if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
-			uffs_EccMake(buf->header, size, ecc_buf);
-		
-		// will auto select ops->ReadPageSpareWithLayout() or ops->ReadPageSpare()
-		ret = uffs_FlashReadPageSpare(dev, block, page, NULL, ecc_store);
-		
-		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-			is_bad = U_TRUE;
-
-		if (UFFS_FLASH_HAVE_ERR(ret))
-			goto ext;
-
-		ret = uffs_EccCorrect(buf->header, size, ecc_store, ecc_buf);
-		ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
-				(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
-
-		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-			is_bad = U_TRUE;
-
-		if (UFFS_FLASH_HAVE_ERR(ret))
-			goto ext;
-	}
-
-ext:
-	if (is_bad) {
-		uffs_BadBlockAdd(dev, block);
-	}
-
-	return ret;
-}
-
-/**
- * make spare from tag and ecc
- *
- * \param[in] dev uffs dev
- * \param[in] ts uffs tag store, NULL if don't pack tag store
- * \param[in] ecc ecc of data, NULL if don't pack ecc
- * \param[out] spare output buffer
- * \note spare buffer size: dev->mem.spare_data_size, all unpacked bytes will be inited 0xFF
- */
-void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare)
-{
-	u8 *p_ts = (u8 *)ts;
-	int ts_size = TAG_STORE_SIZE;
-	int ecc_size = ECC_SIZE(dev);
-	int n;
-	const u8 *p;
-
-	memset(spare, 0xFF, dev->mem.spare_data_size);	// initialize as 0xFF.
-
-	// load ecc
-	p = dev->attr->ecc_layout;
-	if (p && ecc) {
-		while (*p != 0xFF && ecc_size > 0) {
-			n = (p[1] > ecc_size ? ecc_size : p[1]);
-			memcpy(spare + p[0], ecc, n);
-			ecc_size -= n;
-			ecc += n;
-			p += 2;
-		}
-	}
-
-	p = dev->attr->data_layout;
-	while (*p != 0xFF && ts_size > 0) {
-		n = (p[1] > ts_size ? ts_size : p[1]);
-		memcpy(spare + p[0], p_ts, n);
-		ts_size -= n;
-		p_ts += n;
-		p += 2;
-	}
-}
-
-/**
- * write the whole page, include data and tag
- *
- * \param[in] dev uffs device
- * \param[in] block
- * \param[in] page
- * \param[in] buf contains data to be wrote
- * \param[in] tag tag to be wrote
- *
- * \return	#UFFS_FLASH_NO_ERR: success.
- *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
- *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
- */
-int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag)
-{
-	uffs_FlashOps *ops = dev->ops;
-	int size = dev->com.pg_size;
-	u8 ecc_buf[MAX_ECC_SIZE];
-	u8 *spare;
-	struct uffs_MiniHeaderSt *header;
-	int ret = UFFS_FLASH_UNKNOWN_ERR;
-	UBOOL is_bad = U_FALSE;
-
-	uffs_Buf *verify_buf;
-
-	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
-	if (spare == NULL)
-		goto ext;
-
-	// setup header
-	header = HEADER(buf);
-	memset(header, 0xFF, sizeof(struct uffs_MiniHeaderSt));
-	header->status = 0;
-
-	// setup tag
-	tag->s.dirty = TAG_DIRTY;		//!< set dirty bit
-	tag->s.valid = TAG_VALID;		//!< set valid bit
-	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
-		TagMakeEcc(&tag->s);
-	else
-		tag->s.tag_ecc = TAG_ECC_DEFAULT;
-	
-	if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
-		uffs_EccMake(buf->header, size, ecc_buf);
-
-	if (ops->WriteFullPage) {
-		ret = ops->WriteFullPage(dev, block, page, buf->header, size, (u8 *)&(tag->s), TAG_STORE_SIZE, ecc_buf);
-	}
-	else {	
-		ret = ops->WritePageData(dev, block, page, buf->header, size, ecc_buf);
-		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-			is_bad = U_TRUE;
-
-		if (UFFS_FLASH_HAVE_ERR(ret))
-			goto ext;
-
-		if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
-			if (dev->attr->ecc_opt == UFFS_ECC_SOFT ||
-				dev->attr->ecc_opt == UFFS_ECC_HW) {
-				uffs_FlashMakeSpare(dev, &tag->s, ecc_buf, spare);
-			}
-			else
-				uffs_FlashMakeSpare(dev, &tag->s, NULL, spare);
-
-			ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_TRUE);
-		}
-		else {
-			uffs_Assert(dev->attr->layout_opt == UFFS_LAYOUT_FLASH && ops->WriteFullPage != NULL,
-						"Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
-		}
-	}
-	
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		is_bad = U_TRUE;
-
-#ifdef CONFIG_PAGE_WRITE_VERIFY
-	if (!UFFS_FLASH_HAVE_ERR(ret)) {
-		verify_buf = uffs_BufClone(dev, NULL);
-		if (verify_buf) {
-			ret = uffs_FlashReadPage(dev, block, page, verify_buf);
-			if (!UFFS_FLASH_HAVE_ERR(ret)) {
-				if (memcmp(buf->header, verify_buf->header, size) != 0) {
-					uffs_Perror(UFFS_ERR_NORMAL, "Page write verify fail (block %d page %d)", block, page);
-					ret = UFFS_FLASH_BAD_BLK;
-				}
-			}
-			uffs_BufFreeClone(dev, verify_buf);
-		}
-	}
-#endif
-ext:
-	if (is_bad)
-		uffs_BadBlockAdd(dev, block);
-
-	if (spare)
-		uffs_PoolPut(SPOOL(dev), spare);
-
-	return ret;
-}
-
-/**
- * mark a clean page as 'dirty' (and 'invalid')
- *
- * \param[in] dev uffs device
- * \param[in] block
- * \param[in] page
- *
- * \return	#UFFS_FLASH_NO_ERR: success.
- *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
- *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
- */
-int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page)
-{
-	u8 *spare;
-	struct uffs_TagStoreSt s;
-	uffs_FlashOps *ops = dev->ops;
-	UBOOL is_bad = U_FALSE;
-	int ret = UFFS_FLASH_UNKNOWN_ERR;
-
-	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
-	if (spare == NULL)
-		goto ext;
-
-	memset(&s, 0xFF, sizeof(s));
-	s.dirty = TAG_DIRTY;  // set only 'dirty' bit
-	
-	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
-		TagMakeEcc(&s);
-
-	if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
-		uffs_FlashMakeSpare(dev, &s, NULL, spare);
-		ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_FALSE);
-	}
-	else {
-		uffs_Assert(ops->WriteFullPage, "Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
-		ret = ops->WriteFullPage(dev, block, page, NULL, 0, (u8 *)&s, TAG_STORE_SIZE, NULL);
-	}
-
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		is_bad = U_TRUE;
-
-ext:
-	if (is_bad)
-		uffs_BadBlockAdd(dev, block);
-
-	if (spare)
-		uffs_PoolPut(SPOOL(dev), spare);
-
-	return ret;
-}
-
-/** Mark this block as bad block */
-URET uffs_FlashMarkBadBlock(uffs_Device *dev, int block)
-{
-	u8 status = 0;
-	int ret;
-
-	uffs_Perror(UFFS_ERR_NORMAL, "Mark bad block: %d", block);
-
-	if (dev->ops->MarkBadBlock)
-		return dev->ops->MarkBadBlock(dev, block) == 0 ? U_SUCC : U_FAIL;
-
-#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
-	ret = dev->ops->EraseBlock(dev, block);
-	if (ret != UFFS_FLASH_IO_ERR) {  // note: event EraseBlock return UFFS_FLASH_BAD_BLK, we still process it ...
-#endif
-
-	ret = dev->ops->WritePageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1, U_FALSE);
-
-#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
-	}
-#endif
-
-	return ret == UFFS_FLASH_NO_ERR ? U_SUCC : U_FAIL;
-}
-
-/** Is this block a bad block ? */
-UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block)
-{
-	u8 status = 0xFF;
-
-	if (dev->ops->IsBadBlock) /* if flash driver provide 'IsBadBlock' function, then use it. */
-		return dev->ops->IsBadBlock(dev, block) == 0 ? U_FALSE : U_TRUE;
-
-	/* otherwise we check the 'status' byte of spare */
-	/* check the first page */
-	dev->ops->ReadPageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1);
-
-	if (status == 0xFF) {
-		/* check the second page */
-		dev->ops->ReadPageSpare(dev, block, 1, &status, dev->attr->block_status_offs, 1);
-		if (status == 0xFF)
-			return U_FALSE;
-	}
-
-	return U_TRUE;
-}
-
-/** Erase flash block */
-URET uffs_FlashEraseBlock(uffs_Device *dev, int block)
-{
-	int ret;
-
-	ret = dev->ops->EraseBlock(dev, block);
-
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		uffs_BadBlockAdd(dev, block);
-
-	return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_flash.c
+ * \brief UFFS flash interface
+ * \author Ricky Zheng, created 17th July, 2009
+ */
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_ecc.h"
+#include "uffs/uffs_flash.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_badblock.h"
+#include <string.h>
+
+#define PFX "Flash: "
+
+#define SPOOL(dev) &((dev)->mem.spare_pool)
+#define HEADER(buf) ((struct uffs_MiniHeaderSt *)(buf)->header)
+
+#define ECC_SIZE(dev) (3 * (dev)->attr->page_data_size / 256)
+#define TAG_STORE_SIZE	(sizeof(struct uffs_TagStoreSt))
+
+
+static void TagMakeEcc(struct uffs_TagStoreSt *ts)
+{
+	ts->tag_ecc = 0xFFF;
+	ts->tag_ecc = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
+}
+
+static int TagEccCorrect(struct uffs_TagStoreSt *ts)
+{
+	u16 ecc_store, ecc_read;
+	int ret;
+
+	ecc_store = ts->tag_ecc;
+	ts->tag_ecc = 0xFFF;
+	ecc_read = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
+	ret = uffs_EccCorrect8(ts, ecc_read, ecc_store, sizeof(struct uffs_TagStoreSt));
+	ts->tag_ecc = ecc_store;	// restore tag ecc
+
+	return ret;
+
+}
+
+/** setup UFFS spare data & ecc layout */
+static void InitSpareLayout(uffs_Device *dev)
+{
+	u8 s; // status byte offset
+	u8 *p;
+
+	s = dev->attr->block_status_offs;
+
+	if (s < TAG_STORE_SIZE) {	/* status byte is within 0 ~ TAG_STORE_SIZE-1 */
+
+		/* spare data layout */
+		p = dev->attr->_uffs_data_layout;
+		if (s > 0) {
+			*p++ = 0;
+			*p++ = s;
+		}
+		*p++ = s + 1;
+		*p++ = TAG_STORE_SIZE - s;
+		*p++ = 0xFF;
+		*p++ = 0;
+
+		/* spare ecc layout */
+		p = dev->attr->_uffs_ecc_layout;
+		*p++ = TAG_STORE_SIZE + 1;
+		*p++ = ECC_SIZE(dev);
+		*p++ = 0xFF;
+		*p++ = 0;
+	}
+	else {	/* status byte > TAG_STORE_SIZE-1 */
+
+		/* spare data layout */
+		p = dev->attr->_uffs_data_layout;
+		*p++ = 0;
+		*p++ = TAG_STORE_SIZE;
+		*p++ = 0xFF;
+		*p++ = 0;
+
+		/* spare ecc layout */
+		p = dev->attr->_uffs_ecc_layout;
+		if (s < TAG_STORE_SIZE + ECC_SIZE(dev)) {
+			if (s > TAG_STORE_SIZE) {
+				*p++ = TAG_STORE_SIZE;
+				*p++ = s - TAG_STORE_SIZE;
+			}
+			*p++ = s + 1;
+			*p++ = TAG_STORE_SIZE + ECC_SIZE(dev) - s;
+		}
+		else {
+			*p++ = TAG_STORE_SIZE;
+			*p++ = ECC_SIZE(dev);
+		}
+		*p++ = 0xFF;
+		*p++ = 0;
+	}
+
+	dev->attr->data_layout = dev->attr->_uffs_data_layout;
+	dev->attr->ecc_layout = dev->attr->_uffs_ecc_layout;
+}
+
+static int CalculateSpareDataSize(uffs_Device *dev)
+{
+	const u8 *p;
+	int ecc_last = 0, tag_last = 0;
+	int ecc_size, tag_size;
+	int n;
+
+	ecc_size = ECC_SIZE(dev);
+	
+	p = dev->attr->ecc_layout;
+	if (p) {
+		while (*p != 0xFF && ecc_size > 0) {
+			n = (p[1] > ecc_size ? ecc_size : p[1]);
+			ecc_last = p[0] + n;
+			ecc_size -= n;
+			p += 2;
+		}
+	}
+
+	tag_size = TAG_STORE_SIZE;
+	p = dev->attr->data_layout;
+	if (p) {
+		while (*p != 0xFF && tag_size > 0) {
+			n = (p[1] > tag_size ? tag_size : p[1]);
+			tag_last = p[0] + n;
+			tag_size -= n;
+			p += 2;
+		}
+	}
+
+	n = (ecc_last > tag_last ? ecc_last : tag_last);
+	n = (n > dev->attr->block_status_offs + 1 ? n : dev->attr->block_status_offs + 1);
+
+	return n;
+}
+
+
+/**
+ * Initialize UFFS flash interface
+ */
+URET uffs_FlashInterfaceInit(uffs_Device *dev)
+{
+	struct uffs_StorageAttrSt *attr = dev->attr;
+	uffs_Pool *pool = SPOOL(dev);
+
+	if (!dev->ops->IsBadBlock && !dev->ops->ReadPageSpare) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'IsBadBlock' or 'ReadPageSpare' function!");
+		return U_FAIL;
+	}
+
+	if (!dev->ops->MarkBadBlock && !dev->ops->WritePageSpare && !dev->ops->WriteFullPage) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'MarkBadBlock' or 'WritePageSpare' or 'WriteFullPage' function!");
+		return U_FAIL;
+	}
+
+	if (dev->mem.spare_pool_size == 0) {
+		if (dev->mem.malloc) {
+			dev->mem.spare_pool_buf = dev->mem.malloc(dev, UFFS_SPARE_BUFFER_SIZE);
+			if (dev->mem.spare_pool_buf)
+				dev->mem.spare_pool_size = UFFS_SPARE_BUFFER_SIZE;
+		}
+	}
+
+	if (UFFS_SPARE_BUFFER_SIZE > dev->mem.spare_pool_size) {
+		uffs_Perror(UFFS_ERR_DEAD, "Spare buffer require %d but only %d available.", UFFS_SPARE_BUFFER_SIZE, dev->mem.spare_pool_size);
+		memset(pool, 0, sizeof(uffs_Pool));
+		return U_FAIL;
+	}
+
+	uffs_Perror(UFFS_ERR_NOISY, "alloc spare buffers %d bytes.", UFFS_SPARE_BUFFER_SIZE);
+	uffs_PoolInit(pool, dev->mem.spare_pool_buf, dev->mem.spare_pool_size, UFFS_MAX_SPARE_SIZE, MAX_SPARE_BUFFERS);
+
+	if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
+		/* sanity check */
+		if ((dev->attr->data_layout && !dev->attr->ecc_layout) ||
+			(!dev->attr->data_layout && dev->attr->ecc_layout)) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "Please setup data_layout and ecc_layout, or leave them all NULL !");
+			return U_FAIL;
+		}
+
+		if (!attr->data_layout && !attr->ecc_layout)
+			InitSpareLayout(dev);
+	}
+
+	dev->mem.spare_data_size = CalculateSpareDataSize(dev);
+
+	return U_SUCC;
+}
+
+/**
+ * Release UFFS flash interface
+ */
+URET uffs_FlashInterfaceRelease(uffs_Device *dev)
+{
+	uffs_Pool *pool;
+	
+	pool = SPOOL(dev);
+	if (pool->mem && dev->mem.free) {
+		dev->mem.free(dev, pool->mem);
+		pool->mem = NULL;
+		dev->mem.spare_pool_size = 0;
+	}
+	uffs_PoolRelease(pool);
+	memset(pool, 0, sizeof(uffs_Pool));
+
+	return U_SUCC;
+}
+
+/**
+ * unload spare to tag and ecc.
+ */
+static void UnloadSpare(uffs_Device *dev, const u8 *spare, uffs_Tags *tag, u8 *ecc)
+{
+	u8 *p_tag = (u8 *)&tag->s;
+	int tag_size = TAG_STORE_SIZE;
+	int ecc_size = ECC_SIZE(dev);
+	int n;
+	const u8 *p;
+
+	// unload ecc
+	p = dev->attr->ecc_layout;
+	if (p && ecc) {
+		while (*p != 0xFF && ecc_size > 0) {
+			n = (p[1] > ecc_size ? ecc_size : p[1]);
+			memcpy(ecc, spare + p[0], n);
+			ecc_size -= n;
+			ecc += n;
+			p += 2;
+		}
+	}
+
+	// unload tag
+	if (tag) {
+		p = dev->attr->data_layout;
+		while (*p != 0xFF && tag_size > 0) {
+			n = (p[1] > tag_size ? tag_size : p[1]);
+			memcpy(p_tag, spare + p[0], n);
+			tag_size -= n;
+			p_tag += n;
+			p += 2;
+		}
+
+		tag->block_status = spare[dev->attr->block_status_offs];
+	}
+}
+
+/**
+ * Read tag and ecc from page spare
+ *
+ * \param[in] dev uffs device
+ * \param[in] block flash block num
+ * \param[in] page flash page num
+ * \param[out] tag tag to be filled
+ * \param[out] ecc ecc to be filled
+ *
+ * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
+ *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+ *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
+ *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
+*/
+int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc)
+{
+	uffs_FlashOps *ops = dev->ops;
+//	struct uffs_StorageAttrSt *attr = dev->attr;
+	u8 * spare_buf;
+	int ret = UFFS_FLASH_UNKNOWN_ERR;
+	UBOOL is_bad = U_FALSE;
+
+	spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev));
+	if (spare_buf == NULL)
+		goto ext;
+
+	if (ops->ReadPageSpareWithLayout)
+		ret = ops->ReadPageSpareWithLayout(dev, block, page, (u8 *)&tag->s, tag ? TAG_STORE_SIZE : 0, ecc);
+	else
+		ret = ops->ReadPageSpare(dev, block, page, spare_buf, 0, dev->mem.spare_data_size);
+
+
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		is_bad = U_TRUE;
+
+	if (!ops->ReadPageSpareWithLayout)
+		UnloadSpare(dev, spare_buf, tag, ecc);
+
+	// copy some raw data
+	if (tag) {
+		tag->_dirty = tag->s.dirty;
+		tag->_valid = tag->s.valid;
+	}
+
+	if (UFFS_FLASH_HAVE_ERR(ret))
+		goto ext;
+
+	if (tag) {
+		if (tag->_valid == 1) //it's not a valid page ? don't need go further
+			goto ext;
+
+		// do tag ecc correction
+		if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
+			ret = TagEccCorrect(&tag->s);
+			ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
+					(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
+
+			if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+				is_bad = U_TRUE;
+
+			if (UFFS_FLASH_HAVE_ERR(ret))
+				goto ext;
+		}
+	}
+
+ext:
+	if (is_bad) {
+		uffs_BadBlockAdd(dev, block);
+		uffs_Perror(UFFS_ERR_NORMAL, "A new bad block (%d) is detected.", block);
+	}
+
+	if (spare_buf)
+		uffs_PoolPut(SPOOL(dev), spare_buf);
+
+	return ret;
+}
+
+/**
+ * Read page data to page buf and calculate ecc.
+ * \param[in] dev uffs device
+ * \param[in] block flash block num
+ * \param[in] page flash page num of the block
+ * \param[out] buf holding the read out data
+ *
+ * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
+ *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+ *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
+ *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
+ */
+int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf)
+{
+	uffs_FlashOps *ops = dev->ops;
+	int size = dev->com.pg_size;
+	u8 ecc_buf[MAX_ECC_SIZE];
+	u8 ecc_store[MAX_ECC_SIZE];
+	UBOOL is_bad = U_FALSE;
+
+	int ret;
+
+	// if ecc_opt is UFFS_ECC_HW, flash driver return ecc,
+	// if ecc_opt is UFFS_ECC_HW_AUTO, flash driver should do ecc correction.
+	ret = ops->ReadPageData(dev, block, page, buf->header, size, ecc_buf);
+	
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		is_bad = U_TRUE;
+
+	if (UFFS_FLASH_HAVE_ERR(ret))
+		goto ext;
+
+	if (dev->attr->ecc_opt == UFFS_ECC_SOFT || dev->attr->ecc_opt == UFFS_ECC_HW) {
+	  
+		if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
+			uffs_EccMake(buf->header, size, ecc_buf);
+		
+		// will auto select ops->ReadPageSpareWithLayout() or ops->ReadPageSpare()
+		ret = uffs_FlashReadPageSpare(dev, block, page, NULL, ecc_store);
+		
+		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+			is_bad = U_TRUE;
+
+		if (UFFS_FLASH_HAVE_ERR(ret))
+			goto ext;
+
+		ret = uffs_EccCorrect(buf->header, size, ecc_store, ecc_buf);
+		ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
+				(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
+
+		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+			is_bad = U_TRUE;
+
+		if (UFFS_FLASH_HAVE_ERR(ret))
+			goto ext;
+	}
+
+ext:
+	if (is_bad) {
+		uffs_BadBlockAdd(dev, block);
+	}
+
+	return ret;
+}
+
+/**
+ * make spare from tag and ecc
+ *
+ * \param[in] dev uffs dev
+ * \param[in] ts uffs tag store, NULL if don't pack tag store
+ * \param[in] ecc ecc of data, NULL if don't pack ecc
+ * \param[out] spare output buffer
+ * \note spare buffer size: dev->mem.spare_data_size, all unpacked bytes will be inited 0xFF
+ */
+void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare)
+{
+	u8 *p_ts = (u8 *)ts;
+	int ts_size = TAG_STORE_SIZE;
+	int ecc_size = ECC_SIZE(dev);
+	int n;
+	const u8 *p;
+
+	memset(spare, 0xFF, dev->mem.spare_data_size);	// initialize as 0xFF.
+
+	// load ecc
+	p = dev->attr->ecc_layout;
+	if (p && ecc) {
+		while (*p != 0xFF && ecc_size > 0) {
+			n = (p[1] > ecc_size ? ecc_size : p[1]);
+			memcpy(spare + p[0], ecc, n);
+			ecc_size -= n;
+			ecc += n;
+			p += 2;
+		}
+	}
+
+	p = dev->attr->data_layout;
+	while (*p != 0xFF && ts_size > 0) {
+		n = (p[1] > ts_size ? ts_size : p[1]);
+		memcpy(spare + p[0], p_ts, n);
+		ts_size -= n;
+		p_ts += n;
+		p += 2;
+	}
+}
+
+/**
+ * write the whole page, include data and tag
+ *
+ * \param[in] dev uffs device
+ * \param[in] block
+ * \param[in] page
+ * \param[in] buf contains data to be wrote
+ * \param[in] tag tag to be wrote
+ *
+ * \return	#UFFS_FLASH_NO_ERR: success.
+ *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+ *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
+ */
+int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag)
+{
+	uffs_FlashOps *ops = dev->ops;
+	int size = dev->com.pg_size;
+	u8 ecc_buf[MAX_ECC_SIZE];
+	u8 *spare;
+	struct uffs_MiniHeaderSt *header;
+	int ret = UFFS_FLASH_UNKNOWN_ERR;
+	UBOOL is_bad = U_FALSE;
+
+	uffs_Buf *verify_buf;
+
+	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
+	if (spare == NULL)
+		goto ext;
+
+	// setup header
+	header = HEADER(buf);
+	memset(header, 0xFF, sizeof(struct uffs_MiniHeaderSt));
+	header->status = 0;
+
+	// setup tag
+	tag->s.dirty = TAG_DIRTY;		//!< set dirty bit
+	tag->s.valid = TAG_VALID;		//!< set valid bit
+	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
+		TagMakeEcc(&tag->s);
+	else
+		tag->s.tag_ecc = TAG_ECC_DEFAULT;
+	
+	if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
+		uffs_EccMake(buf->header, size, ecc_buf);
+
+	if (ops->WriteFullPage) {
+		ret = ops->WriteFullPage(dev, block, page, buf->header, size, (u8 *)&(tag->s), TAG_STORE_SIZE, ecc_buf);
+	}
+	else {	
+		ret = ops->WritePageData(dev, block, page, buf->header, size, ecc_buf);
+		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+			is_bad = U_TRUE;
+
+		if (UFFS_FLASH_HAVE_ERR(ret))
+			goto ext;
+
+		if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
+			if (dev->attr->ecc_opt == UFFS_ECC_SOFT ||
+				dev->attr->ecc_opt == UFFS_ECC_HW) {
+				uffs_FlashMakeSpare(dev, &tag->s, ecc_buf, spare);
+			}
+			else
+				uffs_FlashMakeSpare(dev, &tag->s, NULL, spare);
+
+			ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_TRUE);
+		}
+		else {
+			uffs_Assert(dev->attr->layout_opt == UFFS_LAYOUT_FLASH && ops->WriteFullPage != NULL,
+						"Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
+		}
+	}
+	
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		is_bad = U_TRUE;
+
+#ifdef CONFIG_PAGE_WRITE_VERIFY
+	if (!UFFS_FLASH_HAVE_ERR(ret)) {
+		verify_buf = uffs_BufClone(dev, NULL);
+		if (verify_buf) {
+			ret = uffs_FlashReadPage(dev, block, page, verify_buf);
+			if (!UFFS_FLASH_HAVE_ERR(ret)) {
+				if (memcmp(buf->header, verify_buf->header, size) != 0) {
+					uffs_Perror(UFFS_ERR_NORMAL, "Page write verify fail (block %d page %d)", block, page);
+					ret = UFFS_FLASH_BAD_BLK;
+				}
+			}
+			uffs_BufFreeClone(dev, verify_buf);
+		}
+	}
+#endif
+ext:
+	if (is_bad)
+		uffs_BadBlockAdd(dev, block);
+
+	if (spare)
+		uffs_PoolPut(SPOOL(dev), spare);
+
+	return ret;
+}
+
+/**
+ * mark a clean page as 'dirty' (and 'invalid')
+ *
+ * \param[in] dev uffs device
+ * \param[in] block
+ * \param[in] page
+ *
+ * \return	#UFFS_FLASH_NO_ERR: success.
+ *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
+ *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
+ */
+int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page)
+{
+	u8 *spare;
+	struct uffs_TagStoreSt s;
+	uffs_FlashOps *ops = dev->ops;
+	UBOOL is_bad = U_FALSE;
+	int ret = UFFS_FLASH_UNKNOWN_ERR;
+
+	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
+	if (spare == NULL)
+		goto ext;
+
+	memset(&s, 0xFF, sizeof(s));
+	s.dirty = TAG_DIRTY;  // set only 'dirty' bit
+	
+	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
+		TagMakeEcc(&s);
+
+	if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
+		uffs_FlashMakeSpare(dev, &s, NULL, spare);
+		ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_FALSE);
+	}
+	else {
+		uffs_Assert(ops->WriteFullPage, "Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
+		ret = ops->WriteFullPage(dev, block, page, NULL, 0, (u8 *)&s, TAG_STORE_SIZE, NULL);
+	}
+
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		is_bad = U_TRUE;
+
+ext:
+	if (is_bad)
+		uffs_BadBlockAdd(dev, block);
+
+	if (spare)
+		uffs_PoolPut(SPOOL(dev), spare);
+
+	return ret;
+}
+
+/** Mark this block as bad block */
+URET uffs_FlashMarkBadBlock(uffs_Device *dev, int block)
+{
+	u8 status = 0;
+	int ret;
+
+	uffs_Perror(UFFS_ERR_NORMAL, "Mark bad block: %d", block);
+
+	if (dev->ops->MarkBadBlock)
+		return dev->ops->MarkBadBlock(dev, block) == 0 ? U_SUCC : U_FAIL;
+
+#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
+	ret = dev->ops->EraseBlock(dev, block);
+	if (ret != UFFS_FLASH_IO_ERR) {  // note: event EraseBlock return UFFS_FLASH_BAD_BLK, we still process it ...
+#endif
+
+	ret = dev->ops->WritePageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1, U_FALSE);
+
+#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
+	}
+#endif
+
+	return ret == UFFS_FLASH_NO_ERR ? U_SUCC : U_FAIL;
+}
+
+/** Is this block a bad block ? */
+UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block)
+{
+	u8 status = 0xFF;
+
+	if (dev->ops->IsBadBlock) /* if flash driver provide 'IsBadBlock' function, then use it. */
+		return dev->ops->IsBadBlock(dev, block) == 0 ? U_FALSE : U_TRUE;
+
+	/* otherwise we check the 'status' byte of spare */
+	/* check the first page */
+	dev->ops->ReadPageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1);
+
+	if (status == 0xFF) {
+		/* check the second page */
+		dev->ops->ReadPageSpare(dev, block, 1, &status, dev->attr->block_status_offs, 1);
+		if (status == 0xFF)
+			return U_FALSE;
+	}
+
+	return U_TRUE;
+}
+
+/** Erase flash block */
+URET uffs_FlashEraseBlock(uffs_Device *dev, int block)
+{
+	int ret;
+
+	ret = dev->ops->EraseBlock(dev, block);
+
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		uffs_BadBlockAdd(dev, block);
+
+	return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
+}
+

+ 1644 - 1627
components/dfs/filesystems/uffs/src/uffs/uffs_fs.c

@@ -1,1627 +1,1644 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_fs.c
- * \brief basic file operations
- * \author Ricky Zheng, created 12th May, 2005
- */
-
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_pool.h"
-#include "uffs/uffs_ecc.h"
-#include "uffs/uffs_badblock.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_mtb.h"
-#include <string.h> 
-#include <stdio.h>
-
-#define PFX "fs:"
-
-#define GET_OBJ_NODE_SERIAL(obj) ((obj)->type == UFFS_TYPE_DIR ? \
-									(obj)->node->u.dir.serial \
-										: \
-									(obj)->node->u.file.serial \
-								   )
-
-#define GET_OBJ_NODE_FATHER(obj) ((obj)->type == UFFS_TYPE_DIR ? \
-									(obj)->node->u.dir.parent \
-										: \
-									(obj)->node->u.file.parent \
-								   )
-
-#define GET_SERIAL_FROM_OBJECT(obj) ((obj)->node ? GET_OBJ_NODE_SERIAL(obj) : obj->serial)
-#define GET_FATHER_FROM_OBJECT(obj) ((obj)->node ? GET_OBJ_NODE_FATHER(obj) : obj->parent)
-
-
-#define GET_BLOCK_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? \
-									(obj)->node->u.dir.block : (obj)->node->u.file.block)
-
-static void do_ReleaseObjectResource(uffs_Object *obj);
-static URET do_TruncateObject(uffs_Object *obj, u32 remain, UBOOL dry_run);
-
-
-static int _object_data[sizeof(uffs_Object) * MAX_OBJECT_HANDLE / sizeof(int)];
-
-static uffs_Pool _object_pool;
-
-
-uffs_Pool * uffs_GetObjectPool(void)
-{
-	return &_object_pool;
-}
-
-/**
- * initialise object buffers, called by UFFS internal
- */
-URET uffs_InitObjectBuf(void)
-{
-	return uffs_PoolInit(&_object_pool, _object_data, sizeof(_object_data),
-			sizeof(uffs_Object), MAX_OBJECT_HANDLE);
-}
-
-/**
- * Release object buffers, called by UFFS internal
- */
-URET uffs_ReleaseObjectBuf(void)
-{
-	return uffs_PoolRelease(&_object_pool);
-}
-
-/**
- * alloc a new object structure
- * \return the new object
- */
-uffs_Object * uffs_GetObject(void)
-{
-	uffs_Object * obj;
-
-	obj = (uffs_Object *) uffs_PoolGet(&_object_pool);
-	if (obj) {
-		memset(obj, 0, sizeof(uffs_Object));
-		obj->attr_loaded = U_FALSE;
-		obj->open_succ = U_FALSE;
-	}
-
-	return obj;
-}
-
-/**
- * re-initialize an object.
- *
- * \return U_SUCC or U_FAIL if the object is openned.
- */
-URET uffs_ReInitObject(uffs_Object *obj)
-{
-	if (obj == NULL)
-		return U_FAIL;
-
-	if (obj->open_succ == U_TRUE)
-		return U_FAIL;	// can't re-init an openned object.
-
-	memset(obj, 0, sizeof(uffs_Object));
-	obj->attr_loaded = U_FALSE;
-	obj->open_succ = U_FALSE;
-
-	return U_SUCC;	
-}
-
-/**
- * put the object struct back to system
- */
-void uffs_PutObject(uffs_Object *obj)
-{
-	if (obj)
-		uffs_PoolPut(&_object_pool, obj);
-}
-
-/**
- * \return the internal index num of object
- */
-int uffs_GetObjectIndex(uffs_Object *obj)
-{
-	return uffs_PoolGetIndex(&_object_pool, obj);
-}
-
-/**
- * \return the object by the internal index
- */
-uffs_Object * uffs_GetObjectByIndex(int idx)
-{
-	return (uffs_Object *) uffs_PoolGetBufByIndex(&_object_pool, idx);
-}
-
-static void uffs_ObjectDevLock(uffs_Object *obj)
-{
-	if (obj) {
-		if (obj->dev) {
-			uffs_DeviceLock(obj->dev);
-			obj->dev_lock_count++;
-		}
-	}
-}
-
-static void uffs_ObjectDevUnLock(uffs_Object *obj)
-{
-	if (obj) {
-		if (obj->dev) {
-			obj->dev_lock_count--;
-			uffs_DeviceUnLock(obj->dev);
-		}
-	}
-} 
-
-
-
-/**
- * create a new object and open it if success
- */
-URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag)
-{
-	oflag |= UO_CREATE;
-
-	if (uffs_ParseObject(obj, fullname) == U_SUCC)
-		uffs_CreateObjectEx(obj, obj->dev, obj->parent, obj->name, obj->name_len, oflag);
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-
-
-/**
- * return the dir length from a path.
- * for example, path = "abc/def/xyz", return 8 ("abc/def/")
- */
-static int GetDirLengthFromPath(const char *path, int path_len)
-{
-	const char *p = path;
-
-	if (path_len > 0) {
-		if (path[path_len - 1] == '/')
-			path_len--;		// skip the last '/'
-
-		p = path + path_len - 1;
-		while (p > path && *p != '/')
-			p--; 
-	}
-
-	return p - path;
-}
-
-/**
- * Create an object under the given dir.
- *
- * \param[in|out] obj to be created, obj is returned from uffs_GetObject()
- * \param[in] dev uffs device
- * \param[in] dir object parent dir serial NO.
- * \param[in] name point to the object name
- * \param[in] name_len object name length
- * \param[in] oflag open flag. UO_DIR should be passed for an dir object.
- *
- * \return U_SUCC or U_FAIL (error code in obj->err).
- */
-URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev, 
-								   int dir, const char *name, int name_len, int oflag)
-{
-	uffs_Buf *buf = NULL;
-	uffs_FileInfo fi;
-	TreeNode *node;
-
-	obj->dev = dev;
-	obj->parent = dir;
-	obj->type = (oflag & UO_DIR ? UFFS_TYPE_DIR : UFFS_TYPE_FILE);
-	obj->name = name;
-	obj->name_len = name_len;
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		if (name[obj->name_len - 1] == '/')
-			obj->name_len--;
-	}
-	else {
-		if (name[obj->name_len - 1] == '/') {
-			obj->err = UENOENT;
-			goto ext;
-		}
-	}
-
-	if (obj->name_len == 0) {
-		obj->err = UENOENT;
-		goto ext;
-	}
-
-	obj->sum = (obj->name_len > 0 ? uffs_MakeSum16(obj->name, obj->name_len) : 0);
-
-	uffs_ObjectDevLock(obj);
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		//find out whether have file with the same name
-		node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-		if (node != NULL) {
-			obj->err = UEEXIST;	// we can't create a dir has the same name with exist file.
-			goto ext_1;
-		}
-		obj->node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-		if (obj->node != NULL) {
-			obj->err = UEEXIST; // we can't create a dir already exist.
-			goto ext_1;
-		}
-	}
-	else {
-		//find out whether have dir with the same name
-		node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-		if (node != NULL) {
-			obj->err = UEEXIST;
-			goto ext_1;
-		}
-		obj->node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-		if (obj->node) {
-			/* file already exist, truncate it to zero length */
-			obj->serial = GET_OBJ_NODE_SERIAL(obj);
-			obj->open_succ = U_TRUE; // set open_succ to U_TRUE before call do_TruncateObject()
-			if (do_TruncateObject(obj, 0, U_TRUE) == U_SUCC)
-				do_TruncateObject(obj, 0, U_FALSE);
-			goto ext_1;
-		}
-	}
-
-	/* dir|file does not exist, create a new one */
-	obj->serial = uffs_FindFreeFsnSerial(obj->dev);
-	if (obj->serial == INVALID_UFFS_SERIAL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "No free serial num!");
-		obj->err = UENOMEM;
-		goto ext_1;
-	}
-
-	if (obj->dev->tree.erased_count < MINIMUN_ERASED_BLOCK) {
-		uffs_Perror(UFFS_ERR_NOISY, "insufficient block in create obj");
-		obj->err = UENOMEM;
-		goto ext_1;
-	}
-
-	buf = uffs_BufNew(obj->dev, obj->type, obj->parent, obj->serial, 0);
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Can't create new buffer when create obj!");
-		goto ext_1;
-	}
-
-	memset(&fi, 0, sizeof(uffs_FileInfo));
-	memcpy(fi.name, obj->name, obj->name_len);
-	fi.name[obj->name_len] = '\0';
-	fi.name_len = obj->name_len;
-	fi.access = 0;
-	fi.attr |= FILE_ATTR_WRITE;
-
-	if (obj->type == UFFS_TYPE_DIR)
-		fi.attr |= FILE_ATTR_DIR;
-
-	fi.create_time = fi.last_modify = uffs_GetCurDateTime();
-
-	uffs_BufWrite(obj->dev, buf, &fi, 0, sizeof(uffs_FileInfo));
-	uffs_BufPut(obj->dev, buf);
-
-	//flush buffer immediately, so that the new node will be inserted into the tree
-	uffs_BufFlushGroup(obj->dev, obj->parent, obj->serial);
-
-	//update obj->node: after buf flushed, the NEW node can be found in the tree
-	if (obj->type == UFFS_TYPE_DIR)
-		obj->node = uffs_TreeFindDirNode(obj->dev, obj->serial);
-	else
-		obj->node = uffs_TreeFindFileNode(obj->dev, obj->serial);
-
-	if (obj->node == NULL) {
-		uffs_Perror(UFFS_ERR_NOISY, "Can't find the node in the tree ?");
-		obj->err = UEIOERR;
-		goto ext_1;
-	}
-
-	if (obj->type == UFFS_TYPE_FILE)
-		obj->node->u.file.len = 0;	//init the length to 0
-
-	if (HAVE_BADBLOCK(obj->dev))
-		uffs_BadBlockRecover(obj->dev);
-
-	obj->open_succ = U_TRUE;
-
-ext_1:
-	uffs_ObjectDevUnLock(obj);
-ext:
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-/**
- * Open object under the given dir.
- *
- * \param[in|out] obj to be open, obj is returned from uffs_GetObject()
- * \param[in] dev uffs device
- * \param[in] dir object parent dir serial NO.
- * \param[in] name point to the object name
- * \param[in] name_len object name length
- * \param[in] oflag open flag. UO_DIR should be passed for an dir object.
- *
- * \return U_SUCC or U_FAIL (error code in obj->err).
- */
-URET uffs_OpenObjectEx(uffs_Object *obj, uffs_Device *dev, 
-								   int dir, const char *name, int name_len, int oflag)
-{
-
-	obj->err = UENOERR;
-	obj->open_succ = U_FALSE;
-
-	if (dev == NULL) {
-		obj->err = UEINVAL;
-		goto ext;
-	}
-
-	if ((oflag & (UO_WRONLY | UO_RDWR)) == (UO_WRONLY | UO_RDWR)) {
-		/* UO_WRONLY and UO_RDWR can't appear together */
-		uffs_Perror(UFFS_ERR_NOISY, "UO_WRONLY and UO_RDWR can't appear together");
-		obj->err = UEINVAL;
-		goto ext;
-	}
-
-	obj->oflag = oflag;
-	obj->parent = dir;
-	obj->type = (oflag & UO_DIR ? UFFS_TYPE_DIR : UFFS_TYPE_FILE);
-	obj->pos = 0;
-	obj->dev = dev;
-	obj->name = name;
-	obj->name_len = name_len;
-
-	// adjust the name length
-	if (obj->type == UFFS_TYPE_DIR) {
-		if (obj->name_len > 0 && name[obj->name_len - 1] == '/')
-			obj->name_len--;	// truncate the ending '/' for dir
-	}
-
-	obj->sum = (obj->name_len > 0 ? uffs_MakeSum16(name, obj->name_len) : 0);
-	obj->head_pages = obj->dev->attr->pages_per_block - 1;
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		if (obj->name_len == 0) {
-			if (dir != PARENT_OF_ROOT) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "Bad parent for root dir!");
-				obj->err = UEINVAL;
-			}
-			else {
-				obj->serial = ROOT_DIR_SERIAL;
-			}
-			goto ext;
-		}
-	}
-	else {
-		if (obj->name_len == 0 || name[obj->name_len - 1] == '/') {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Bad file name.");
-			obj->err = UEINVAL;
-		}
-	}
-
-
-	uffs_ObjectDevLock(obj);
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		obj->node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-	}
-	else {
-		obj->node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
-	}
-
-	if (obj->node == NULL) {			// dir or file not exist
-		if (obj->oflag & UO_CREATE) {	// expect to create a new one
-			uffs_ObjectDevUnLock(obj);
-			if (obj->name == NULL || obj->name_len == 0)
-				obj->err = UEEXIST;
-			else
-				uffs_CreateObjectEx(obj, dev, dir, obj->name, obj->name_len, oflag);
-			goto ext;
-		}
-		else {
-			obj->err = UENOENT;
-			goto ext_1;
-		}
-	}
-
-	if ((obj->oflag & (UO_CREATE | UO_EXCL)) == (UO_CREATE | UO_EXCL)){
-		obj->err = UEEXIST;
-		goto ext_1;
-	}
-
-	obj->serial = GET_OBJ_NODE_SERIAL(obj);
-	obj->open_succ = U_TRUE;
-
-	if (obj->oflag & UO_TRUNC)
-		if (do_TruncateObject(obj, 0, U_TRUE) == U_SUCC) //NOTE: obj->err will be set in do_TruncateObject() if failed.
-			do_TruncateObject(obj, 0, U_FALSE);
-
-ext_1:
-	uffs_ObjectDevUnLock(obj);
-ext:
-	obj->open_succ = (obj->err == UENOERR ? U_TRUE : U_FALSE);
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-
-/**
- * Parse the full path name, initialize obj.
- *
- * \param[out] obj object to be initialize.
- * \param[in] name full path name.
- *
- * \return U_SUCC if the name is parsed correctly,
- *			 U_FAIL if failed, and obj->err is set.
- *
- *	\note the following fields in obj will be initialized:
- *			obj->dev
- *			obj->parent
- *			obj->name
- *			obj->name_len
- */
-URET uffs_ParseObject(uffs_Object *obj, const char *name)
-{
-	int len, m_len, d_len;
-	uffs_Device *dev;
-	const char *start, *p, *dname;
-	u16 dir;
-	TreeNode *node;
-	u16 sum;
-
-	if (uffs_ReInitObject(obj) == U_FAIL)
-		return U_FAIL;
-
-	len = strlen(name);
-	m_len = uffs_GetMatchedMountPointSize(name);
-	dev = uffs_GetDeviceFromMountPointEx(name, m_len);
-
-	if (dev) {
-		start = name + m_len;
-		d_len = GetDirLengthFromPath(start, len - m_len);
-		p = start;
-		obj->dev = dev;
-		if (m_len == len) {
-			obj->parent = PARENT_OF_ROOT;
-			obj->name = NULL;
-			obj->name_len = 0;
-		}
-		else {
-			dir = ROOT_DIR_SERIAL;
-			dname = start;
-			while (p - start < d_len) {
-				while (*p != '/') p++;
-				sum = uffs_MakeSum16(dname, p - dname);
-				node = uffs_TreeFindDirNodeByName(dev, dname, p - dname, sum, dir);
-				if (node == NULL) {
-					obj->err = UENOENT;
-					break;
-				}
-				else {
-					dir = node->u.dir.serial;
-					p++; // skip the '/'
-					dname = p;
-				}
-			}
-			obj->parent = dir;
-			obj->name = start + (d_len > 0 ? d_len + 1 : 0);
-			obj->name_len = len - (d_len > 0 ? d_len + 1 : 0) - m_len;
-		}
-	}
-	else {
-		obj->err = UENOENT;
-	}
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-/**
- * Open a UFFS object
- *
- * \param[in|out] obj the object to be open
- * \param[in] name the full name of the object
- * \param[in] oflag open flag
- *
- * \return U_SUCC if object is opened successfully,
- *			 U_FAIL if failed, error code will be set to obj->err.
- */
-URET uffs_OpenObject(uffs_Object *obj, const char *name, int oflag)
-{
-	if (obj == NULL)
-		return U_FAIL;
-
- 	if (uffs_ParseObject(obj, name) == U_SUCC)
-		uffs_OpenObjectEx(obj, obj->dev, obj->parent, obj->name, obj->name_len, oflag);
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-
-static void do_ReleaseObjectResource(uffs_Object *obj)
-{
-	if (obj) {
-		if (obj->dev) {
-			if (HAVE_BADBLOCK(obj->dev))
-				uffs_BadBlockRecover(obj->dev);
-			if (obj->dev_lock_count > 0) {
-				uffs_ObjectDevUnLock(obj);
-			}
-			uffs_PutDevice(obj->dev);
-			obj->dev = NULL;
-			obj->open_succ = U_FALSE;
-		}
-	}
-}
-
-
-static URET do_FlushObject(uffs_Object *obj)
-{
-	uffs_Device *dev;
-	URET ret = U_SUCC;
-
-	dev = obj->dev;
-	if (obj->node) {
-		if (obj->type == UFFS_TYPE_DIR)
-			ret = uffs_BufFlushGroup(dev, obj->node->u.dir.parent, obj->node->u.dir.serial);
-		else {
-			ret = (
-				uffs_BufFlushGroupMatchParent(dev, obj->node->u.file.serial) == U_SUCC &&
-				uffs_BufFlushGroup(dev, obj->node->u.file.parent, obj->node->u.file.serial) == U_SUCC
-				) ? U_SUCC : U_FAIL;
-		}
-	}
-
-	return ret;
-}
-
-/**
- * Flush object data.
- *
- * \param[in] obj object to be flushed
- * \return U_SUCC or U_FAIL (error code in obj->err).
- */
-URET uffs_FlushObject(uffs_Object *obj)
-{
-	uffs_Device *dev;
-
-	if(obj->dev == NULL || obj->open_succ != U_TRUE) {
-		obj->err = UEBADF;
-		goto ext;
-	}
-
-	dev = obj->dev;
-	uffs_ObjectDevLock(obj);
-
-	if (do_FlushObject(obj) != U_SUCC)
-		obj->err = UEIOERR;
-
-	uffs_ObjectDevUnLock(obj);
-
-ext:
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-/**
- * Close an openned object.
- *
- * \param[in] obj object to be closed
- * \return U_SUCC or U_FAIL (error code in obj->err).
- */
-URET uffs_CloseObject(uffs_Object *obj)
-{
-	uffs_Device *dev;
-#ifdef CONFIG_CHANGE_MODIFY_TIME
-	uffs_Buf *buf;
-	uffs_FileInfo fi;
-#endif
-
-	if(obj->dev == NULL || obj->open_succ != U_TRUE) {
-		obj->err = UEBADF;
-		goto ext;
-	}
-
-	dev = obj->dev;
-	uffs_ObjectDevLock(obj);
-
-	if (obj->oflag & (UO_WRONLY|UO_RDWR|UO_APPEND|UO_CREATE|UO_TRUNC)) {
-
-#ifdef CONFIG_CHANGE_MODIFY_TIME
-		if (obj->node) {
-			//need to change the last modify time stamp
-			if (obj->type == UFFS_TYPE_DIR)
-				buf = uffs_BufGetEx(dev, UFFS_TYPE_DIR, obj->node, 0);
-			else
-				buf = uffs_BufGetEx(dev, UFFS_TYPE_FILE, obj->node, 0);
-
-			if(buf == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't get file header");
-				do_FlushObject(obj);
-				uffs_ObjectDevUnLock(obj);
-				goto ext;
-			}
-			uffs_BufRead(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
-			fi.last_modify = uffs_GetCurDateTime();
-			uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
-			uffs_BufPut(dev, buf);
-		}
-#endif
-		do_FlushObject(obj);
-	}
-
-	uffs_ObjectDevUnLock(obj);
-
-ext:
-	do_ReleaseObjectResource(obj);
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-static u16 GetFdnByOfs(uffs_Object *obj, u32 ofs)
-{
-	uffs_Device *dev = obj->dev;
-
-	if (ofs < (u32)(obj->head_pages * dev->com.pg_data_size)) {
-		return 0;
-	}
-	else {
-		ofs -= obj->head_pages * dev->com.pg_data_size;
-		return (ofs / (dev->com.pg_data_size * dev->attr->pages_per_block)) + 1;
-	}
-}
-
-
-static u32 GetStartOfDataBlock(uffs_Object *obj, u16 fdn)
-{
-	if (fdn == 0) {
-		return 0;
-	}
-	else {
-		return (obj->head_pages * obj->dev->com.pg_data_size) +
-			(fdn - 1) * (obj->dev->com.pg_data_size * obj->dev->attr->pages_per_block);
-	}
-}
-
-
-static int do_WriteNewBlock(uffs_Object *obj,
-						  const void *data, u32 len,
-						  u16 parent,
-						  u16 serial)
-{
-	uffs_Device *dev = obj->dev;
-	u16 page_id;
-	int wroteSize = 0;
-	int size;
-	uffs_Buf *buf;
-	URET ret;
-
-	for (page_id = 0; page_id < dev->attr->pages_per_block; page_id++) {
-		size = (len - wroteSize) > dev->com.pg_data_size ?
-					dev->com.pg_data_size : len - wroteSize;
-		if (size <= 0)
-			break;
-
-		buf = uffs_BufNew(dev, UFFS_TYPE_DATA, parent, serial, page_id);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't create a new page ?");
-			break;
-		}
-		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, 0, size);
-		uffs_BufPut(dev, buf);
-
-		if (ret != U_SUCC) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "write data fail!");
-			break;
-		}
-		wroteSize += size;
-		obj->node->u.file.len += size;
-	}
-
-	return wroteSize;
-}
-
-static int do_WriteInternalBlock(uffs_Object *obj,
-							   TreeNode *node,
-							   u16 fdn,
-							   const void *data,
-							   u32 len,
-							   u32 blockOfs)
-{
-	uffs_Device *dev = obj->dev;
-	u16 maxPageID;
-	u16 page_id;
-	u32 size;
-	u32 pageOfs;
-	u32 wroteSize = 0;
-	URET ret;
-	uffs_Buf *buf;
-	u32 block_start;
-	u8 type;
-	u16 parent, serial;
-
-	block_start = GetStartOfDataBlock(obj, fdn);
-
-	if (fdn == 0) {
-		type = UFFS_TYPE_FILE;
-		parent = node->u.file.parent;
-		serial = node->u.file.serial;
-	}
-	else {
-		type = UFFS_TYPE_DATA;
-		parent = node->u.data.parent;
-		serial = fdn;
-	}
-
-	if (fdn == 0)
-		maxPageID = obj->head_pages;
-	else
-		maxPageID = dev->attr->pages_per_block - 1;
-
-
-	while (wroteSize < len) {
-		page_id = blockOfs / dev->com.pg_data_size;
-		if (fdn == 0)
-			page_id++; //in file header, page_id start from 1, not 0.
-		if (page_id > maxPageID) 
-			break;
-
-		pageOfs = blockOfs % dev->com.pg_data_size;
-		size = (len - wroteSize + pageOfs) > dev->com.pg_data_size ?
-					(dev->com.pg_data_size - pageOfs) : (len - wroteSize);
-
-		if ((obj->node->u.file.len % dev->com.pg_data_size) == 0 &&
-			(blockOfs + block_start) == obj->node->u.file.len) {
-
-			buf = uffs_BufNew(dev, type, parent, serial, page_id);
-
-			if(buf == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can create a new buf!");
-				break;
-			}
-		}
-		else {
-			buf = uffs_BufGetEx(dev, type, node, page_id);
-			if (buf == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't get buffer ?");
-				break;
-			}
-		}
-
-		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, pageOfs, size);
-		uffs_BufPut(dev, buf);
-
-		if (ret == U_FAIL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "write inter data fail!");
-			break;
-		}
-
-		wroteSize += size;
-		blockOfs += size;
-
-		if (block_start + blockOfs > obj->node->u.file.len)
-			obj->node->u.file.len = block_start + blockOfs;
-
-	}
-
-	return wroteSize;
-}
-
-
-
-/**
- * write data to obj, from obj->pos
- *
- * \param[in] obj file obj
- * \param[in] data data pointer
- * \param[in] len length of data to be write
- *
- * \return bytes wrote to obj
- */
-int uffs_WriteObject(uffs_Object *obj, const void *data, int len)
-{
-	uffs_Device *dev = obj->dev;
-	TreeNode *fnode = obj->node;
-	int remain = len;
-	u16 fdn;
-	u32 write_start;
-	TreeNode *dnode;
-	u32 size;
-
-	if (obj == NULL) 
-		return 0;
-
-	if (obj->dev == NULL || obj->open_succ != U_TRUE) {
-		obj->err = UEBADF;
-		return 0;
-	}
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		uffs_Perror(UFFS_ERR_NOISY, "Can't write to an dir object!");
-		obj->err = UEACCES;
-		return 0;
-	}
-
-	if (obj->pos > fnode->u.file.len) {
-		return 0; //can't write file out of range
-	}
-
-	if (obj->oflag == UO_RDONLY) {
-		obj->err = UEACCES;
-		return 0;
-	}
-
-	uffs_ObjectDevLock(obj);
-
-	if (obj->oflag & UO_APPEND)
-		obj->pos = fnode->u.file.len;
-
-	while (remain > 0) {
-		write_start = obj->pos + len - remain;
-		if (write_start > fnode->u.file.len) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "write point out of file ?");
-			break;
-		}
-
-		fdn = GetFdnByOfs(obj, write_start);
-
-		if (write_start == fnode->u.file.len && fdn > 0 &&
-			write_start == GetStartOfDataBlock(obj, fdn)) {
-			if (dev->tree.erased_count < MINIMUN_ERASED_BLOCK) {
-				uffs_Perror(UFFS_ERR_NOISY, "insufficient block in write obj, new block");
-				break;
-			}
-			size = do_WriteNewBlock(obj, (u8 *)data + len - remain, remain, fnode->u.file.serial, fdn);
-
-			//Flush immediately, so that the new data node will be created and put in the tree.
-			uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);
-
-			if (size == 0) 
-				break;
-
-			remain -= size;
-		}
-		else {
-
-			if(fdn == 0)
-				dnode = obj->node;
-			else
-				dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
-
-			if(dnode == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node in tree ?");
-				obj->err = UEUNKNOWN;
-				break;
-			}
-			size = do_WriteInternalBlock(obj, dnode, fdn,
-									(u8 *)data + len - remain, remain,
-									write_start - GetStartOfDataBlock(obj, fdn));
-#ifdef CONFIG_FLUSH_BUF_AFTER_WRITE
-			uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);
-#endif
-			if (size == 0)
-				break;
-
-			remain -= size;
-		}
-	}
-
-	obj->pos += (len - remain);
-
-	if (HAVE_BADBLOCK(dev))
-		uffs_BadBlockRecover(dev);
-
-	uffs_ObjectDevUnLock(obj);
-
-	return len - remain;
-}
-
-/**
- * read data from obj
- *
- * \param[in] obj uffs object
- * \param[out] data output data buffer
- * \param[in] len required length of data to be read from object->pos
- *
- * \return return bytes of data have been read
- */
-int uffs_ReadObject(uffs_Object *obj, void *data, int len)
-{
-	uffs_Device *dev = obj->dev;
-	TreeNode *fnode = obj->node;
-	u32 remain = len;
-	u16 fdn;
-	u32 read_start;
-	TreeNode *dnode;
-	u32 size;
-	uffs_Buf *buf;
-	u32 blockOfs;
-	u16 page_id;
-	u8 type;
-	u32 pageOfs;
-
-	if (obj == NULL)
-		return 0;
-
-	if (obj->dev == NULL || obj->open_succ == U_FALSE) {
-		obj->err = UEBADF;
-		return 0;
-	}
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		uffs_Perror(UFFS_ERR_NOISY, "Can't read data from a dir object!");
-		obj->err = UEBADF;
-		return 0;
-	}
-
-	if (obj->pos > fnode->u.file.len) {
-		return 0; //can't read file out of range
-	}
-
-	if (obj->oflag & UO_WRONLY) {
-		obj->err = UEACCES;
-		return 0;
-	}
-
-	uffs_ObjectDevLock(obj);
-
-	while (remain > 0) {
-		read_start = obj->pos + len - remain;
-		if (read_start >= fnode->u.file.len) {
-			//uffs_Perror(UFFS_ERR_NOISY, "read point out of file ?");
-			break;
-		}
-
-		fdn = GetFdnByOfs(obj, read_start);
-		if (fdn == 0) {
-			dnode = obj->node;
-			type = UFFS_TYPE_FILE;
-		}
-		else {
-			type = UFFS_TYPE_DATA;
-			dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
-			if (dnode == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't get data node in entry!");
-				obj->err = UEUNKNOWN;
-				break;
-			}
-		}
-
-		blockOfs = GetStartOfDataBlock(obj, fdn);
-		page_id = (read_start - blockOfs) / dev->com.pg_data_size;
-
-		if (fdn == 0) {
-			/**
-			 * fdn == 0: this means that the reading is start from the first block,
-			 * since the page 0 is for file attr, so we move to the next page ID.
-			 */
-			page_id++;
-		}
-
-		buf = uffs_BufGetEx(dev, type, dnode, (u16)page_id);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't get buffer when read obj.");
-			obj->err = UEIOERR;
-			break;
-		}
-
-		pageOfs = read_start % dev->com.pg_data_size;
-		if (pageOfs >= buf->data_len) {
-			//uffs_Perror(UFFS_ERR_NOISY, "read data out of page range ?");
-			uffs_BufPut(dev, buf);
-			break;
-		}
-		size = (remain + pageOfs > buf->data_len ? buf->data_len - pageOfs : remain);
-
-		uffs_BufRead(dev, buf, (u8 *)data + len - remain, pageOfs, size);
-		uffs_BufPut(dev, buf);
-
-		remain -= size;
-	}
-
-	obj->pos += (len - remain);
-
-	if (HAVE_BADBLOCK(dev)) 
-		uffs_BadBlockRecover(dev);
-
-	uffs_ObjectDevUnLock(obj);
-
-	return len - remain;
-}
-
-/**
- * move the file pointer
- *
- * \param[in] obj uffs object
- * \param[in] offset offset from origin
- * \param[in] origin the origin position, one of:
- *
- * \return return the new file pointer position
- */
-long uffs_SeekObject(uffs_Object *obj, long offset, int origin)
-{
-	if (obj->type == UFFS_TYPE_DIR) {
-		uffs_Perror(UFFS_ERR_NOISY, "Can't seek a dir object!");
-		return 0;
-	}
-
-	uffs_ObjectDevLock(obj);
-
-	switch (origin) {
-		case USEEK_CUR:
-			if (obj->pos + offset > obj->node->u.file.len) {
-				obj->pos = obj->node->u.file.len;
-			}
-			else {
-				obj->pos += offset;
-			}
-			break;
-		case USEEK_SET:
-			if (offset > (long) obj->node->u.file.len) {
-				obj->pos = obj->node->u.file.len;
-			}
-			else {
-				obj->pos = offset;
-			}
-			break;
-		case USEEK_END:
-			if ( offset>0 ) {
-				obj->pos = obj->node->u.file.len;
-			}
-			else if((offset >= 0 ? offset : -offset) > (long) obj->node->u.file.len) {
-				obj->pos = 0;
-			}
-			else {
-				obj->pos = obj->node->u.file.len + offset;
-			}
-			break;
-	}
-
-	uffs_ObjectDevUnLock(obj);
-
-	return (long) obj->pos;
-}
-
-/**
- * get current file pointer
- *
- * \param[in] obj uffs object
- *
- * \return return the file pointer position if the obj is valid, return -1 if obj is invalid.
- */
-int uffs_GetCurOffset(uffs_Object *obj)
-{
-	if (obj) {
-		if (obj->dev && obj->open_succ == U_TRUE)
-			return obj->pos;
-	}
-	return -1;
-}
-
-/**
- * check whether the file pointer is at the end of file
- *
- * \param[in] obj uffs object
- *
- * \return return 1 if file pointer is at the end of file, return -1 if error occur, else return 0.
- */
-int uffs_EndOfFile(uffs_Object *obj)
-{
-	if (obj) {
-		if (obj->dev && obj->type == UFFS_TYPE_FILE && obj->open_succ == U_TRUE) {
-			if (obj->pos >= obj->node->u.file.len) {
-				return 1;
-			}
-			else {
-				return 0;
-			}
-		}
-	}
-
-	return -1;
-}
-
-static URET do_TruncateInternalWithBlockRecover(uffs_Object *obj, u16 fdn, u32 remain, UBOOL dry_run)
-{
-	uffs_Device *dev = obj->dev;
-	TreeNode *fnode = obj->node;
-	u16 page_id, max_page_id;
-	TreeNode *node;
-	uffs_Buf *buf = NULL;
-	u8 type;
-	u32 block_start;
-	u16 parent, serial;
-	int slot;
-
-	if (fdn == 0) {
-		node = fnode;
-		type = UFFS_TYPE_FILE;
-		max_page_id = obj->head_pages;
-		block_start = 0;
-		parent = node->u.file.parent;
-		serial = node->u.file.serial;
-	}
-	else {
-		node = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
-		if (node == NULL) {
-			obj->err = UEIOERR;
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node when truncate obj");
-			goto ext;
-		}
-		type = UFFS_TYPE_DATA;
-		max_page_id = dev->attr->pages_per_block - 1;
-		block_start = obj->head_pages * dev->com.pg_data_size +  (fdn - 1) * dev->com.pg_data_size * dev->attr->pages_per_block;
-		parent = node->u.data.parent;
-		serial = node->u.data.serial;
-	}
-
-	if (dry_run == U_TRUE) {
-		// checking the buffer. this is the main reason why we need the 'dry run' mode.
-		for (page_id = 0; page_id <= max_page_id; page_id++) {
-			buf = uffs_BufFind(dev, parent, serial, page_id);
-			if (buf) {								//!< ok, the buffer was loaded before ...
-				if (uffs_BufIsFree(buf) == U_FALSE) {
-					obj->err = UEEXIST;
-					break;						//!< and someone is still holding the buffer, can't truncate it !!!
-				}
-			}
-		}
-		buf = NULL;
-		goto ext;
-	}
-	
-	// find the last page after truncate
-	for (page_id = (fdn == 0 ? 1 : 0); page_id <= max_page_id; page_id++) {
-		if (block_start + (page_id + 1) * dev->com.pg_data_size >= remain)
-			break;
-	}
-
-	if (page_id > max_page_id) {
-		obj->err = UEUNKNOWN;
-		uffs_Perror(UFFS_ERR_SERIOUS, "Overflow");
-		goto ext;
-	}
-
-	// flush buffer before performing block recovery
-	uffs_BufFlushGroup(dev, parent, serial);
-
-	// load the last page
-	buf = uffs_BufGetEx(dev, type, node, page_id);
-	if (buf == NULL) {
-		obj->err = UENOMEM;
-		uffs_Perror(UFFS_ERR_SERIOUS, "Can't get buf");
-		goto ext;
-	}
-
-	uffs_BufWrite(dev, buf, NULL, 0, 0); // just make this buf dirty
-
-	// lock the group
-	slot = uffs_BufFindGroupSlot(dev, parent, serial);
-	uffs_BufLockGroup(dev, slot);
-
-	if (remain == 0)
-		buf->data_len = 0;
-	else {
-		remain = (remain % dev->com.pg_data_size);
-		buf->data_len = (remain == 0 ? dev->com.pg_data_size : 0);
-	}
-	buf->ext_mark |= UFFS_BUF_EXT_MARK_TRUNC_TAIL;
-	uffs_BufPut(dev, buf);
-
-	// invalidate the rest page buf
-	page_id++;
-	for (; page_id <= max_page_id; page_id++) {
-		buf = uffs_BufFind(dev, parent, serial, page_id);
-		if (buf)
-			uffs_BufMarkEmpty(dev, buf);
-	}
-
-	// flush dirty buffer immediately, forcing block recovery.
-	uffs_BufFlushGroupEx(dev, parent, serial, U_TRUE);
-
-	// unlock the group
-	uffs_BufUnLockGroup(dev, slot);
-
-ext:
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-/**
- * truncate an object
- *
- * \param[in] obj object to be truncated
- * \param[in] remain data bytes to be remained in this object
- *
- * \return U_SUCC or U_FAIL (error code in obj->err)
- */
-URET uffs_TruncateObject(uffs_Object *obj, u32 remain)
-{
-	uffs_ObjectDevLock(obj);
-	if (do_TruncateObject(obj, remain, U_TRUE) == U_SUCC)
-		do_TruncateObject(obj, remain, U_FALSE);
-	uffs_ObjectDevUnLock(obj);
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-
-/** truncate obj without lock device */
-static URET do_TruncateObject(uffs_Object *obj, u32 remain, UBOOL dry_run)
-{
-	uffs_Device *dev = obj->dev;
-	TreeNode *fnode = obj->node;
-	u16 fdn;
-	u32 flen;
-	u32 block_start;
-	TreeNode *node;
-	uffs_BlockInfo *bc;
-	uffs_Buf *buf;
-	u16 page;
-
-	if (obj->dev == NULL || obj->open_succ == U_FALSE || fnode == NULL) {
-		obj->err = UEBADF;
-		goto ext;
-	}
-
-	/* can't truncate a dir */
-	/* TODO: delete files under dir ? */
-	if (obj->type == UFFS_TYPE_DIR) {
-		obj->err = UEEXIST;
-		goto ext;
-	}
-
-	if (remain >= fnode->u.file.len) {
-		goto ext;	//!< nothing to do ... 
-	}
-
-	flen = fnode->u.file.len;
-
-	while (flen > remain) {
-		fdn = GetFdnByOfs(obj, flen - 1);
-
-		//uffs_BufFlushGroup(dev, obj->serial, fdn);	//!< flush the buffer
-
-		block_start = GetStartOfDataBlock(obj, fdn);
-		if (remain <= block_start && fdn > 0) {
-			node = uffs_TreeFindDataNode(dev, obj->serial, fdn);
-			if (node == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node when trancate obj.");
-				obj->err = UEIOERR;
-				goto ext;
-			}
-			bc = uffs_BlockInfoGet(dev, node->u.data.block);
-			if (bc == NULL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "can't get block info when trancate obj.");
-				obj->err = UEIOERR;
-				goto ext;
-			}
-
-			for (page = 0; page < dev->attr->pages_per_block; page++) {
-				buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page);
-				if (buf) {								//!< ok, the buffer was loaded before ...
-					if (uffs_BufIsFree(buf) == U_FALSE) {
-						uffs_BlockInfoPut(dev, bc);
-						goto ext;						//!< and someone is still holding the buffer, can't truncate it !!!
-					}
-					else if (dry_run == U_FALSE)
-						uffs_BufMarkEmpty(dev, buf);	//!< discard the buffer
-				}
-			}
-
-			if (dry_run == U_FALSE) {
-				uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-				uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node);
-				uffs_FlashEraseBlock(dev, bc->block);
-				node->u.list.block = bc->block;
-				if (HAVE_BADBLOCK(dev))
-					uffs_BadBlockProcess(dev, node);
-				else
-					uffs_TreeInsertToErasedListTail(dev, node);
-
-				uffs_BlockInfoPut(dev, bc);
-				fnode->u.file.len = block_start;
-			}
-			else {
-				uffs_BlockInfoPut(dev, bc);
-			}
-			flen = block_start;
-		}
-		else {
-			if (do_TruncateInternalWithBlockRecover(obj, fdn, remain, dry_run) == U_SUCC) {
-				if (dry_run == U_FALSE)
-					fnode->u.file.len = remain;
-				flen = remain;
-			}
-		}
-	}
-
-	if (HAVE_BADBLOCK(dev)) 
-		uffs_BadBlockRecover(dev);
-ext:
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-
-}
-
-
-/**
- * \brief delete uffs object
- *
- * \param[in] name full name of object
- * \param[out] err return error code
- *
- * \return U_SUCC if object is deleted successfully. 
- *	return U_FAIL if error happen, error code is set to *err.
- */
-URET uffs_DeleteObject(const char * name, int *err)
-{
-	uffs_Object *obj;
-	TreeNode *node;
-	uffs_Device *dev;
-	u16 block;
-	uffs_Buf *buf;
-	URET ret = U_FAIL;
-
-	obj = uffs_GetObject();
-	if (obj == NULL) {
-		if (err)
-			*err = UEMFILE;
-		goto err1;
-	}
-
-	if (uffs_OpenObject(obj, name, UO_RDWR|UO_DIR) == U_FAIL) {
-		if (uffs_OpenObject(obj, name, UO_RDWR) == U_FAIL) {
-			if (err)
-				*err = UENOENT;
-			goto err1;
-		}
-	}
-
-	uffs_TruncateObject(obj, 0);
-
-	uffs_ObjectDevLock(obj);
-	dev = obj->dev;
-
-	if (obj->type == UFFS_TYPE_DIR) {
-		// if the dir is not empty, can't delete it.
-		node = uffs_TreeFindDirNodeWithParent(dev, obj->serial);
-		if (node != NULL) {
-			if (err)
-				*err = UEACCES;
-			goto err;  //have sub dirs ?
-		}
-
-		node = uffs_TreeFindFileNodeWithParent(dev, obj->serial);
-		if (node != NULL) {
-			if (err)
-				*err = UEACCES;
-			goto err;  //have sub files ?
-		}
-	}
-
-	block = GET_BLOCK_FROM_NODE(obj);
-	node = obj->node;
-
-	// before erase the block, we need to take care of the buffer ...
-	uffs_BufFlushAll(dev);
-
-	if (HAVE_BADBLOCK(dev))
-		uffs_BadBlockRecover(dev);
-
-	buf = uffs_BufFind(dev, obj->parent, obj->serial, 0);
-
-	if (buf) {
-		//need to expire this buffer ...
-		if (buf->ref_count != 0) {
-			//there is other obj for this file still in use ?
-			uffs_Perror(UFFS_ERR_NORMAL, "Try to delete object but still have buf referenced.");
-			if (err)
-				*err = UEACCES;
-			goto err;
-		}
-
-		buf->mark = UFFS_BUF_EMPTY; //!< make this buffer expired.
-	}
-
-	//TODO: need to take care of other obj->node ?
-
-	uffs_BreakFromEntry(dev, obj->type, node);
-	uffs_FlashEraseBlock(dev, block);
-	node->u.list.block = block;
-	if (HAVE_BADBLOCK(dev))
-		uffs_BadBlockProcess(dev, node);
-	else
-		uffs_TreeInsertToErasedListTail(dev, node);
-
-	ret = U_SUCC;
-err:
-	uffs_ObjectDevUnLock(obj);
-err1:
-	do_ReleaseObjectResource(obj);
-
-	uffs_PutObject(obj);
-
-	return ret;
-}
-
-/**
- * Remove object under a new parent, change object name.
- *
- * \param[in|out] obj
- * \param[in] new_parent new parent's serial number
- * \param[in] new_name new name of the object. if new_name == NULL, keep the old name.
- * \param[in] name_len new name length.
- *
- * \return U_SUCC or U_FAIL (obj->err for the reason)
- */
-URET uffs_MoveObjectEx(uffs_Object *obj, int new_parent, const char *new_name, int name_len)
-{
-	uffs_Buf *buf;
-	uffs_FileInfo fi;
-	uffs_Device *dev = obj->dev;
-	TreeNode *node = obj->node;
-
-	if (dev == NULL || node == NULL || obj->open_succ != U_TRUE) {
-		obj->err = UEBADF;
-		goto ext;
-	}
-
-	uffs_ObjectDevLock(obj);
-
-	obj->parent = new_parent;
-
-	if (name_len > 0) {
-
-		buf = uffs_BufGetEx(dev, obj->type, node, 0);
-		if (buf == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't get buf when rename!");
-			obj->err = UEIOERR;
-			goto ext_1;
-		}
-
-		memcpy(&fi, buf->data, sizeof(uffs_FileInfo));
-
-		if (new_name[name_len-1] == '/')
-			name_len--;
-
-		memcpy(fi.name, new_name, name_len);
-		fi.name[name_len] = 0;
-		fi.name_len = name_len;
-		fi.last_modify = uffs_GetCurDateTime();
-
-		buf->parent = new_parent;	// !! need to manually change the 'parent' !!
-		uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
-		uffs_BufPut(dev, buf);
-
-		// !! force a block recover so that all old tag will be expired !!
-		// This is important so we only need to check the first spare when mount UFFS :)
-		uffs_BufFlushGroupEx(dev, obj->parent, obj->serial, U_TRUE);
-
-		obj->name = new_name;
-		obj->name_len = name_len;
-		obj->sum = uffs_MakeSum16(fi.name, fi.name_len);
-	}
-
-	//update the check sum and new parent of tree node
-	if (obj->type == UFFS_TYPE_DIR) {
-		obj->node->u.dir.checksum = obj->sum;
-		obj->node->u.dir.parent = new_parent;
-	}
-	else {
-		obj->node->u.file.checksum = obj->sum;
-		obj->node->u.file.parent = new_parent;
-	}
-
-ext_1:
-	uffs_ObjectDevUnLock(obj);
-ext:
-
-	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
-}
-
-/**
- * \brief rename(move) file or dir.
- * \return U_SUCC if success, otherwise return U_FAIL and set error code to *err.
- * \note rename/move file between different mount point is not allowed.
- */
-URET uffs_RenameObject(const char *old_name, const char *new_name, int *err)
-{
-	uffs_Object *obj = NULL, *new_obj = NULL;
-	URET ret = U_FAIL;
-	int oflag;
-
-	obj = uffs_GetObject();
-	new_obj = uffs_GetObject();
-
-	if (obj == NULL || new_obj == NULL) {
-		if (err) 
-			*err = UEINVAL;
-		goto ext;
-	}
-
-	oflag = UO_RDONLY;
-	if (uffs_OpenObject(new_obj, new_name, oflag) == U_SUCC) {
-		uffs_CloseObject(new_obj);
-		uffs_Perror(UFFS_ERR_NOISY, "new object already exist!");
-		if (err)
-			*err = UEEXIST;
-		goto ext;
-	}
-	oflag |= UO_DIR;
-	if (uffs_OpenObject(new_obj, new_name, oflag) == U_SUCC) {
-		uffs_CloseObject(new_obj);
-		uffs_Perror(UFFS_ERR_NOISY, "new object already exist!");
-		if (err)
-			*err = UEEXIST;
-		goto ext;
-	}
-
-	if (uffs_ParseObject(new_obj, new_name) != U_SUCC) {
-		uffs_Perror(UFFS_ERR_NOISY, "parse new name fail !");
-		if (err)
-			*err = UENOENT;
-		goto ext;
-	}
-
-	if (new_obj->name_len == 0) {
-		uffs_Perror(UFFS_ERR_NOISY, "invalid new name");
-		if (err)
-			*err = UEINVAL;
-		goto ext;
-	}
-
-	oflag = UO_RDONLY;
-	if (uffs_OpenObject(obj, old_name, oflag) != U_SUCC) {
-		oflag |= UO_DIR;
-		if (uffs_OpenObject(obj, old_name, oflag) != U_SUCC) {
-			uffs_Perror(UFFS_ERR_NOISY, "Can't open old object !");
-			if (err)
-				*err = UEACCES;
-			goto ext;
-		}
-	}
-
-	if (obj->dev != new_obj->dev) {
-		uffs_Perror(UFFS_ERR_NOISY, "Can't move object between different mount point");
-		if (err)
-			*err = UEACCES;
-	}
-	else {
-		ret = uffs_MoveObjectEx(obj, new_obj->parent, new_obj->name, new_obj->name_len);
-		if (ret == U_FAIL && err)
-			*err = obj->err;
-	}
-
-	uffs_CloseObject(obj);
-
-ext:
-	if (obj) uffs_PutObject(obj);
-	if (new_obj) uffs_PutObject(new_obj);
-
-	return ret;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fs.c
+ * \brief basic file operations
+ * \author Ricky Zheng, created 12th May, 2005
+ */
+
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_pool.h"
+#include "uffs/uffs_ecc.h"
+#include "uffs/uffs_badblock.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_mtb.h"
+#include <string.h> 
+#include <stdio.h>
+
+#define PFX "fs:"
+
+#define GET_OBJ_NODE_SERIAL(obj) ((obj)->type == UFFS_TYPE_DIR ? \
+									(obj)->node->u.dir.serial \
+										: \
+									(obj)->node->u.file.serial \
+								   )
+
+#define GET_OBJ_NODE_FATHER(obj) ((obj)->type == UFFS_TYPE_DIR ? \
+									(obj)->node->u.dir.parent \
+										: \
+									(obj)->node->u.file.parent \
+								   )
+
+#define GET_SERIAL_FROM_OBJECT(obj) ((obj)->node ? GET_OBJ_NODE_SERIAL(obj) : obj->serial)
+#define GET_FATHER_FROM_OBJECT(obj) ((obj)->node ? GET_OBJ_NODE_FATHER(obj) : obj->parent)
+
+
+#define GET_BLOCK_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? \
+									(obj)->node->u.dir.block : (obj)->node->u.file.block)
+
+static void do_ReleaseObjectResource(uffs_Object *obj);
+static URET do_TruncateObject(uffs_Object *obj, u32 remain, UBOOL dry_run);
+
+
+static int _object_data[sizeof(uffs_Object) * MAX_OBJECT_HANDLE / sizeof(int)];
+
+static uffs_Pool _object_pool;
+
+
+uffs_Pool * uffs_GetObjectPool(void)
+{
+	return &_object_pool;
+}
+
+/**
+ * initialise object buffers, called by UFFS internal
+ */
+URET uffs_InitObjectBuf(void)
+{
+	return uffs_PoolInit(&_object_pool, _object_data, sizeof(_object_data),
+			sizeof(uffs_Object), MAX_OBJECT_HANDLE);
+}
+
+/**
+ * Release object buffers, called by UFFS internal
+ */
+URET uffs_ReleaseObjectBuf(void)
+{
+	return uffs_PoolRelease(&_object_pool);
+}
+
+/**
+ * alloc a new object structure
+ * \return the new object
+ */
+uffs_Object * uffs_GetObject(void)
+{
+	uffs_Object * obj;
+
+	obj = (uffs_Object *) uffs_PoolGet(&_object_pool);
+	if (obj) {
+		memset(obj, 0, sizeof(uffs_Object));
+		obj->attr_loaded = U_FALSE;
+		obj->open_succ = U_FALSE;
+	}
+
+	return obj;
+}
+
+/**
+ * re-initialize an object.
+ *
+ * \return U_SUCC or U_FAIL if the object is openned.
+ */
+URET uffs_ReInitObject(uffs_Object *obj)
+{
+	if (obj == NULL)
+		return U_FAIL;
+
+	if (obj->open_succ == U_TRUE)
+		return U_FAIL;	// can't re-init an openned object.
+
+	memset(obj, 0, sizeof(uffs_Object));
+	obj->attr_loaded = U_FALSE;
+	obj->open_succ = U_FALSE;
+
+	return U_SUCC;	
+}
+
+/**
+ * put the object struct back to system
+ */
+void uffs_PutObject(uffs_Object *obj)
+{
+	if (obj)
+		uffs_PoolPut(&_object_pool, obj);
+}
+
+/**
+ * \return the internal index num of object
+ */
+int uffs_GetObjectIndex(uffs_Object *obj)
+{
+	return uffs_PoolGetIndex(&_object_pool, obj);
+}
+
+/**
+ * \return the object by the internal index
+ */
+uffs_Object * uffs_GetObjectByIndex(int idx)
+{
+	return (uffs_Object *) uffs_PoolGetBufByIndex(&_object_pool, idx);
+}
+
+static void uffs_ObjectDevLock(uffs_Object *obj)
+{
+	if (obj) {
+		if (obj->dev) {
+			uffs_DeviceLock(obj->dev);
+			obj->dev_lock_count++;
+		}
+	}
+}
+
+static void uffs_ObjectDevUnLock(uffs_Object *obj)
+{
+	if (obj) {
+		if (obj->dev) {
+			obj->dev_lock_count--;
+			uffs_DeviceUnLock(obj->dev);
+		}
+	}
+} 
+
+
+
+/**
+ * create a new object and open it if success
+ */
+URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag)
+{
+	oflag |= UO_CREATE;
+
+	if (uffs_ParseObject(obj, fullname) == U_SUCC)
+		uffs_CreateObjectEx(obj, obj->dev, obj->parent, obj->name, obj->name_len, oflag);
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+
+
+/**
+ * return the dir length from a path.
+ * for example, path = "abc/def/xyz", return 8 ("abc/def/")
+ */
+static int GetDirLengthFromPath(const char *path, int path_len)
+{
+	const char *p = path;
+
+	if (path_len > 0) {
+		if (path[path_len - 1] == '/')
+			path_len--;		// skip the last '/'
+
+		p = path + path_len - 1;
+		while (p > path && *p != '/')
+			p--; 
+	}
+
+	return p - path;
+}
+
+/**
+ * Create an object under the given dir.
+ *
+ * \param[in|out] obj to be created, obj is returned from uffs_GetObject()
+ * \param[in] dev uffs device
+ * \param[in] dir object parent dir serial NO.
+ * \param[in] name point to the object name
+ * \param[in] name_len object name length
+ * \param[in] oflag open flag. UO_DIR should be passed for an dir object.
+ *
+ * \return U_SUCC or U_FAIL (error code in obj->err).
+ */
+URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev, 
+								   int dir, const char *name, int name_len, int oflag)
+{
+	uffs_Buf *buf = NULL;
+	uffs_FileInfo fi;
+	TreeNode *node;
+
+	obj->dev = dev;
+	obj->parent = dir;
+	obj->type = (oflag & UO_DIR ? UFFS_TYPE_DIR : UFFS_TYPE_FILE);
+	obj->name = name;
+	obj->name_len = name_len;
+
+	if (obj->type == UFFS_TYPE_DIR) 
+	{
+		if (name[obj->name_len - 1] == '/')
+			obj->name_len--;
+	}
+	else 
+	{
+		if (name[obj->name_len - 1] == '/') 
+		{
+			obj->err = UENOENT;
+			goto ext;
+		}
+	}
+
+	if (obj->name_len == 0) 
+	{
+		obj->err = UENOENT;
+		goto ext;
+	}
+
+	obj->sum = (obj->name_len > 0 ? uffs_MakeSum16(obj->name, obj->name_len) : 0);
+
+	uffs_ObjectDevLock(obj);
+
+	if (obj->type == UFFS_TYPE_DIR) 
+	{
+		//find out whether have file with the same name
+		node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+		if (node != NULL) 
+		{
+			obj->err = UEEXIST;	// we can't create a dir has the same name with exist file.
+			goto ext_1;
+		}
+		obj->node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+		if (obj->node != NULL) 
+		{
+			obj->err = UEEXIST; // we can't create a dir already exist.
+			goto ext_1;
+		}
+	}
+	else 
+	{
+		//find out whether have dir with the same name
+		node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+		if (node != NULL) 
+		{
+			obj->err = UEEXIST;
+			goto ext_1;
+		}
+		obj->node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+		if (obj->node) 
+		{
+			/* file already exist, truncate it to zero length */
+			obj->serial = GET_OBJ_NODE_SERIAL(obj);
+			obj->open_succ = U_TRUE; // set open_succ to U_TRUE before call do_TruncateObject()
+			if (do_TruncateObject(obj, 0, U_TRUE) == U_SUCC)
+				do_TruncateObject(obj, 0, U_FALSE);
+			goto ext_1;
+		}
+	}
+
+	/* dir|file does not exist, create a new one */
+	obj->serial = uffs_FindFreeFsnSerial(obj->dev);
+	if (obj->serial == INVALID_UFFS_SERIAL) 
+	{
+		uffs_Perror(UFFS_ERR_SERIOUS, "No free serial num!");
+		obj->err = UENOMEM;
+		goto ext_1;
+	}
+
+	if (obj->dev->tree.erased_count < MINIMUN_ERASED_BLOCK) 
+	{
+		uffs_Perror(UFFS_ERR_NOISY, "insufficient block in create obj");
+		obj->err = UENOMEM;
+		goto ext_1;
+	}
+
+	buf = uffs_BufNew(obj->dev, obj->type, obj->parent, obj->serial, 0);
+	if (buf == NULL) 
+	{
+		uffs_Perror(UFFS_ERR_SERIOUS, "Can't create new buffer when create obj!");
+		goto ext_1;
+	}
+
+	memset(&fi, 0, sizeof(uffs_FileInfo));
+	memcpy(fi.name, obj->name, obj->name_len);
+	fi.name[obj->name_len] = '\0';
+	fi.name_len = obj->name_len;
+	fi.access = 0;
+	fi.attr |= FILE_ATTR_WRITE;
+
+	if (obj->type == UFFS_TYPE_DIR)
+		fi.attr |= FILE_ATTR_DIR;
+
+	fi.create_time = fi.last_modify = uffs_GetCurDateTime();
+
+	uffs_BufWrite(obj->dev, buf, &fi, 0, sizeof(uffs_FileInfo));
+	uffs_BufPut(obj->dev, buf);
+
+	//flush buffer immediately, so that the new node will be inserted into the tree
+	uffs_BufFlushGroup(obj->dev, obj->parent, obj->serial);
+
+	//update obj->node: after buf flushed, the NEW node can be found in the tree
+	if (obj->type == UFFS_TYPE_DIR)
+		obj->node = uffs_TreeFindDirNode(obj->dev, obj->serial);
+	else
+		obj->node = uffs_TreeFindFileNode(obj->dev, obj->serial);
+
+	if (obj->node == NULL) 
+	{
+		uffs_Perror(UFFS_ERR_NOISY, "Can't find the node in the tree ?");
+		obj->err = UEIOERR;
+		goto ext_1;
+	}
+
+	if (obj->type == UFFS_TYPE_FILE)
+		obj->node->u.file.len = 0;	//init the length to 0
+
+	if (HAVE_BADBLOCK(obj->dev))
+		uffs_BadBlockRecover(obj->dev);
+
+	obj->open_succ = U_TRUE;
+
+ext_1:
+	uffs_ObjectDevUnLock(obj);
+ext:
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+/**
+ * Open object under the given dir.
+ *
+ * \param[in|out] obj to be open, obj is returned from uffs_GetObject()
+ * \param[in] dev uffs device
+ * \param[in] dir object parent dir serial NO.
+ * \param[in] name point to the object name
+ * \param[in] name_len object name length
+ * \param[in] oflag open flag. UO_DIR should be passed for an dir object.
+ *
+ * \return U_SUCC or U_FAIL (error code in obj->err).
+ */
+URET uffs_OpenObjectEx(uffs_Object *obj, uffs_Device *dev, 
+								   int dir, const char *name, int name_len, int oflag)
+{
+
+	obj->err = UENOERR;
+	obj->open_succ = U_FALSE;
+
+	if (dev == NULL) {
+		obj->err = UEINVAL;
+		goto ext;
+	}
+
+	if ((oflag & (UO_WRONLY | UO_RDWR)) == (UO_WRONLY | UO_RDWR)) {
+		/* UO_WRONLY and UO_RDWR can't appear together */
+		uffs_Perror(UFFS_ERR_NOISY, "UO_WRONLY and UO_RDWR can't appear together");
+		obj->err = UEINVAL;
+		goto ext;
+	}
+
+	obj->oflag = oflag;
+	obj->parent = dir;
+	obj->type = (oflag & UO_DIR ? UFFS_TYPE_DIR : UFFS_TYPE_FILE);
+	obj->pos = 0;
+	obj->dev = dev;
+	obj->name = name;
+	obj->name_len = name_len;
+
+	// adjust the name length
+	if (obj->type == UFFS_TYPE_DIR) {
+		if (obj->name_len > 0 && name[obj->name_len - 1] == '/')
+			obj->name_len--;	// truncate the ending '/' for dir
+	}
+
+	obj->sum = (obj->name_len > 0 ? uffs_MakeSum16(name, obj->name_len) : 0);
+	obj->head_pages = obj->dev->attr->pages_per_block - 1;
+
+	if (obj->type == UFFS_TYPE_DIR) {
+		if (obj->name_len == 0) {
+			if (dir != PARENT_OF_ROOT) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "Bad parent for root dir!");
+				obj->err = UEINVAL;
+			}
+			else {
+				obj->serial = ROOT_DIR_SERIAL;
+			}
+			goto ext;
+		}
+	}
+	else {
+		if (obj->name_len == 0 || name[obj->name_len - 1] == '/') {
+			uffs_Perror(UFFS_ERR_SERIOUS, "Bad file name.");
+			obj->err = UEINVAL;
+		}
+	}
+
+
+	uffs_ObjectDevLock(obj);
+
+	if (obj->type == UFFS_TYPE_DIR) {
+		obj->node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+	}
+	else {
+		obj->node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent);
+	}
+
+	if (obj->node == NULL) {			// dir or file not exist
+		if (obj->oflag & UO_CREATE) {	// expect to create a new one
+			uffs_ObjectDevUnLock(obj);
+			if (obj->name == NULL || obj->name_len == 0)
+				obj->err = UEEXIST;
+			else
+				uffs_CreateObjectEx(obj, dev, dir, obj->name, obj->name_len, oflag);
+			goto ext;
+		}
+		else {
+			obj->err = UENOENT;
+			goto ext_1;
+		}
+	}
+
+	if ((obj->oflag & (UO_CREATE | UO_EXCL)) == (UO_CREATE | UO_EXCL)){
+		obj->err = UEEXIST;
+		goto ext_1;
+	}
+
+	obj->serial = GET_OBJ_NODE_SERIAL(obj);
+	obj->open_succ = U_TRUE;
+
+	if (obj->oflag & UO_TRUNC)
+		if (do_TruncateObject(obj, 0, U_TRUE) == U_SUCC) //NOTE: obj->err will be set in do_TruncateObject() if failed.
+			do_TruncateObject(obj, 0, U_FALSE);
+
+ext_1:
+	uffs_ObjectDevUnLock(obj);
+ext:
+	obj->open_succ = (obj->err == UENOERR ? U_TRUE : U_FALSE);
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+
+/**
+ * Parse the full path name, initialize obj.
+ *
+ * \param[out] obj object to be initialize.
+ * \param[in] name full path name.
+ *
+ * \return U_SUCC if the name is parsed correctly,
+ *			 U_FAIL if failed, and obj->err is set.
+ *
+ *	\note the following fields in obj will be initialized:
+ *			obj->dev
+ *			obj->parent
+ *			obj->name
+ *			obj->name_len
+ */
+URET uffs_ParseObject(uffs_Object *obj, const char *name)
+{
+	int len, m_len, d_len;
+	uffs_Device *dev;
+	const char *start, *p, *dname;
+	u16 dir;
+	TreeNode *node;
+	u16 sum;
+
+	if (uffs_ReInitObject(obj) == U_FAIL)
+		return U_FAIL;
+
+	len = strlen(name);
+	m_len = uffs_GetMatchedMountPointSize(name);
+	dev = uffs_GetDeviceFromMountPointEx(name, m_len);
+
+	if (dev) {
+		start = name + m_len;
+		d_len = GetDirLengthFromPath(start, len - m_len);
+		p = start;
+		obj->dev = dev;
+		if (m_len == len) {
+			obj->parent = PARENT_OF_ROOT;
+			obj->name = NULL;
+			obj->name_len = 0;
+		}
+		else {
+			dir = ROOT_DIR_SERIAL;
+			dname = start;
+			while (p - start < d_len) {
+				while (*p != '/') p++;
+				sum = uffs_MakeSum16(dname, p - dname);
+				node = uffs_TreeFindDirNodeByName(dev, dname, p - dname, sum, dir);
+				if (node == NULL) {
+					obj->err = UENOENT;
+					break;
+				}
+				else {
+					dir = node->u.dir.serial;
+					p++; // skip the '/'
+					dname = p;
+				}
+			}
+			obj->parent = dir;
+			obj->name = start + (d_len > 0 ? d_len + 1 : 0);
+			obj->name_len = len - (d_len > 0 ? d_len + 1 : 0) - m_len;
+		}
+	}
+	else {
+		obj->err = UENOENT;
+	}
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+/**
+ * Open a UFFS object
+ *
+ * \param[in|out] obj the object to be open
+ * \param[in] name the full name of the object
+ * \param[in] oflag open flag
+ *
+ * \return U_SUCC if object is opened successfully,
+ *			 U_FAIL if failed, error code will be set to obj->err.
+ */
+URET uffs_OpenObject(uffs_Object *obj, const char *name, int oflag)
+{
+	if (obj == NULL)
+		return U_FAIL;
+
+ 	if (uffs_ParseObject(obj, name) == U_SUCC)
+		uffs_OpenObjectEx(obj, obj->dev, obj->parent, obj->name, obj->name_len, oflag);
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+
+static void do_ReleaseObjectResource(uffs_Object *obj)
+{
+	if (obj) {
+		if (obj->dev) {
+			if (HAVE_BADBLOCK(obj->dev))
+				uffs_BadBlockRecover(obj->dev);
+			if (obj->dev_lock_count > 0) {
+				uffs_ObjectDevUnLock(obj);
+			}
+			uffs_PutDevice(obj->dev);
+			obj->dev = NULL;
+			obj->open_succ = U_FALSE;
+		}
+	}
+}
+
+
+static URET do_FlushObject(uffs_Object *obj)
+{
+	uffs_Device *dev;
+	URET ret = U_SUCC;
+
+	dev = obj->dev;
+	if (obj->node) {
+		if (obj->type == UFFS_TYPE_DIR)
+			ret = uffs_BufFlushGroup(dev, obj->node->u.dir.parent, obj->node->u.dir.serial);
+		else {
+			ret = (
+				uffs_BufFlushGroupMatchParent(dev, obj->node->u.file.serial) == U_SUCC &&
+				uffs_BufFlushGroup(dev, obj->node->u.file.parent, obj->node->u.file.serial) == U_SUCC
+				) ? U_SUCC : U_FAIL;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Flush object data.
+ *
+ * \param[in] obj object to be flushed
+ * \return U_SUCC or U_FAIL (error code in obj->err).
+ */
+URET uffs_FlushObject(uffs_Object *obj)
+{
+	uffs_Device *dev;
+	dev = dev;
+	if(obj->dev == NULL || obj->open_succ != U_TRUE) {
+		obj->err = UEBADF;
+		goto ext;
+	}
+
+	dev = obj->dev;
+	uffs_ObjectDevLock(obj);
+
+	if (do_FlushObject(obj) != U_SUCC)
+		obj->err = UEIOERR;
+
+	uffs_ObjectDevUnLock(obj);
+
+ext:
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+/**
+ * Close an openned object.
+ *
+ * \param[in] obj object to be closed
+ * \return U_SUCC or U_FAIL (error code in obj->err).
+ */
+URET uffs_CloseObject(uffs_Object *obj)
+{
+	uffs_Device *dev;
+#ifdef CONFIG_CHANGE_MODIFY_TIME
+	uffs_Buf *buf;
+	uffs_FileInfo fi;
+#endif
+	dev = dev;
+	if(obj->dev == NULL || obj->open_succ != U_TRUE) {
+		obj->err = UEBADF;
+		goto ext;
+	}
+
+	dev = obj->dev;
+	uffs_ObjectDevLock(obj);
+
+	if (obj->oflag & (UO_WRONLY|UO_RDWR|UO_APPEND|UO_CREATE|UO_TRUNC)) {
+
+#ifdef CONFIG_CHANGE_MODIFY_TIME
+		if (obj->node) {
+			//need to change the last modify time stamp
+			if (obj->type == UFFS_TYPE_DIR)
+				buf = uffs_BufGetEx(dev, UFFS_TYPE_DIR, obj->node, 0);
+			else
+				buf = uffs_BufGetEx(dev, UFFS_TYPE_FILE, obj->node, 0);
+
+			if(buf == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't get file header");
+				do_FlushObject(obj);
+				uffs_ObjectDevUnLock(obj);
+				goto ext;
+			}
+			uffs_BufRead(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
+			fi.last_modify = uffs_GetCurDateTime();
+			uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
+			uffs_BufPut(dev, buf);
+		}
+#endif
+		do_FlushObject(obj);
+	}
+
+	uffs_ObjectDevUnLock(obj);
+
+ext:
+	do_ReleaseObjectResource(obj);
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+static u16 GetFdnByOfs(uffs_Object *obj, u32 ofs)
+{
+	uffs_Device *dev = obj->dev;
+
+	if (ofs < (u32)(obj->head_pages * dev->com.pg_data_size)) {
+		return 0;
+	}
+	else {
+		ofs -= obj->head_pages * dev->com.pg_data_size;
+		return (ofs / (dev->com.pg_data_size * dev->attr->pages_per_block)) + 1;
+	}
+}
+
+
+static u32 GetStartOfDataBlock(uffs_Object *obj, u16 fdn)
+{
+	if (fdn == 0) {
+		return 0;
+	}
+	else {
+		return (obj->head_pages * obj->dev->com.pg_data_size) +
+			(fdn - 1) * (obj->dev->com.pg_data_size * obj->dev->attr->pages_per_block);
+	}
+}
+
+
+static int do_WriteNewBlock(uffs_Object *obj,
+						  const void *data, u32 len,
+						  u16 parent,
+						  u16 serial)
+{
+	uffs_Device *dev = obj->dev;
+	u16 page_id;
+	int wroteSize = 0;
+	int size;
+	uffs_Buf *buf;
+	URET ret;
+
+	for (page_id = 0; page_id < dev->attr->pages_per_block; page_id++) {
+		size = (len - wroteSize) > dev->com.pg_data_size ?
+					dev->com.pg_data_size : len - wroteSize;
+		if (size <= 0)
+			break;
+
+		buf = uffs_BufNew(dev, UFFS_TYPE_DATA, parent, serial, page_id);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't create a new page ?");
+			break;
+		}
+		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, 0, size);
+		uffs_BufPut(dev, buf);
+
+		if (ret != U_SUCC) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "write data fail!");
+			break;
+		}
+		wroteSize += size;
+		obj->node->u.file.len += size;
+	}
+
+	return wroteSize;
+}
+
+static int do_WriteInternalBlock(uffs_Object *obj,
+							   TreeNode *node,
+							   u16 fdn,
+							   const void *data,
+							   u32 len,
+							   u32 blockOfs)
+{
+	uffs_Device *dev = obj->dev;
+	u16 maxPageID;
+	u16 page_id;
+	u32 size;
+	u32 pageOfs;
+	u32 wroteSize = 0;
+	URET ret;
+	uffs_Buf *buf;
+	u32 block_start;
+	u8 type;
+	u16 parent, serial;
+
+	block_start = GetStartOfDataBlock(obj, fdn);
+
+	if (fdn == 0) {
+		type = UFFS_TYPE_FILE;
+		parent = node->u.file.parent;
+		serial = node->u.file.serial;
+	}
+	else {
+		type = UFFS_TYPE_DATA;
+		parent = node->u.data.parent;
+		serial = fdn;
+	}
+
+	if (fdn == 0)
+		maxPageID = obj->head_pages;
+	else
+		maxPageID = dev->attr->pages_per_block - 1;
+
+
+	while (wroteSize < len) {
+		page_id = blockOfs / dev->com.pg_data_size;
+		if (fdn == 0)
+			page_id++; //in file header, page_id start from 1, not 0.
+		if (page_id > maxPageID) 
+			break;
+
+		pageOfs = blockOfs % dev->com.pg_data_size;
+		size = (len - wroteSize + pageOfs) > dev->com.pg_data_size ?
+					(dev->com.pg_data_size - pageOfs) : (len - wroteSize);
+
+		if ((obj->node->u.file.len % dev->com.pg_data_size) == 0 &&
+			(blockOfs + block_start) == obj->node->u.file.len) {
+
+			buf = uffs_BufNew(dev, type, parent, serial, page_id);
+
+			if(buf == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can create a new buf!");
+				break;
+			}
+		}
+		else {
+			buf = uffs_BufGetEx(dev, type, node, page_id);
+			if (buf == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't get buffer ?");
+				break;
+			}
+		}
+
+		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, pageOfs, size);
+		uffs_BufPut(dev, buf);
+
+		if (ret == U_FAIL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "write inter data fail!");
+			break;
+		}
+
+		wroteSize += size;
+		blockOfs += size;
+
+		if (block_start + blockOfs > obj->node->u.file.len)
+			obj->node->u.file.len = block_start + blockOfs;
+
+	}
+
+	return wroteSize;
+}
+
+
+
+/**
+ * write data to obj, from obj->pos
+ *
+ * \param[in] obj file obj
+ * \param[in] data data pointer
+ * \param[in] len length of data to be write
+ *
+ * \return bytes wrote to obj
+ */
+int uffs_WriteObject(uffs_Object *obj, const void *data, int len)
+{
+	uffs_Device *dev = obj->dev;
+	TreeNode *fnode = obj->node;
+	int remain = len;
+	u16 fdn;
+	u32 write_start;
+	TreeNode *dnode;
+	u32 size;
+
+	if (obj == NULL) 
+		return 0;
+
+	if (obj->dev == NULL || obj->open_succ != U_TRUE) {
+		obj->err = UEBADF;
+		return 0;
+	}
+
+	if (obj->type == UFFS_TYPE_DIR) {
+		uffs_Perror(UFFS_ERR_NOISY, "Can't write to an dir object!");
+		obj->err = UEACCES;
+		return 0;
+	}
+
+	if (obj->pos > fnode->u.file.len) {
+		return 0; //can't write file out of range
+	}
+
+	if (obj->oflag == UO_RDONLY) {
+		obj->err = UEACCES;
+		return 0;
+	}
+
+	uffs_ObjectDevLock(obj);
+
+	if (obj->oflag & UO_APPEND)
+		obj->pos = fnode->u.file.len;
+
+	while (remain > 0) {
+		write_start = obj->pos + len - remain;
+		if (write_start > fnode->u.file.len) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "write point out of file ?");
+			break;
+		}
+
+		fdn = GetFdnByOfs(obj, write_start);
+
+		if (write_start == fnode->u.file.len && fdn > 0 &&
+			write_start == GetStartOfDataBlock(obj, fdn)) {
+			if (dev->tree.erased_count < MINIMUN_ERASED_BLOCK) {
+				uffs_Perror(UFFS_ERR_NOISY, "insufficient block in write obj, new block");
+				break;
+			}
+			size = do_WriteNewBlock(obj, (u8 *)data + len - remain, remain, fnode->u.file.serial, fdn);
+
+			//Flush immediately, so that the new data node will be created and put in the tree.
+			uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);
+
+			if (size == 0) 
+				break;
+
+			remain -= size;
+		}
+		else {
+
+			if(fdn == 0)
+				dnode = obj->node;
+			else
+				dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
+
+			if(dnode == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node in tree ?");
+				obj->err = UEUNKNOWN;
+				break;
+			}
+			size = do_WriteInternalBlock(obj, dnode, fdn,
+									(u8 *)data + len - remain, remain,
+									write_start - GetStartOfDataBlock(obj, fdn));
+#ifdef CONFIG_FLUSH_BUF_AFTER_WRITE
+			uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);
+#endif
+			if (size == 0)
+				break;
+
+			remain -= size;
+		}
+	}
+
+	obj->pos += (len - remain);
+
+	if (HAVE_BADBLOCK(dev))
+		uffs_BadBlockRecover(dev);
+
+	uffs_ObjectDevUnLock(obj);
+
+	return len - remain;
+}
+
+/**
+ * read data from obj
+ *
+ * \param[in] obj uffs object
+ * \param[out] data output data buffer
+ * \param[in] len required length of data to be read from object->pos
+ *
+ * \return return bytes of data have been read
+ */
+int uffs_ReadObject(uffs_Object *obj, void *data, int len)
+{
+	uffs_Device *dev = obj->dev;
+	TreeNode *fnode = obj->node;
+	u32 remain = len;
+	u16 fdn;
+	u32 read_start;
+	TreeNode *dnode;
+	u32 size;
+	uffs_Buf *buf;
+	u32 blockOfs;
+	u16 page_id;
+	u8 type;
+	u32 pageOfs;
+
+	if (obj == NULL)
+		return 0;
+
+	if (obj->dev == NULL || obj->open_succ == U_FALSE) {
+		obj->err = UEBADF;
+		return 0;
+	}
+
+	if (obj->type == UFFS_TYPE_DIR) {
+		uffs_Perror(UFFS_ERR_NOISY, "Can't read data from a dir object!");
+		obj->err = UEBADF;
+		return 0;
+	}
+
+	if (obj->pos > fnode->u.file.len) {
+		return 0; //can't read file out of range
+	}
+
+	if (obj->oflag & UO_WRONLY) {
+		obj->err = UEACCES;
+		return 0;
+	}
+
+	uffs_ObjectDevLock(obj);
+
+	while (remain > 0) {
+		read_start = obj->pos + len - remain;
+		if (read_start >= fnode->u.file.len) {
+			//uffs_Perror(UFFS_ERR_NOISY, "read point out of file ?");
+			break;
+		}
+
+		fdn = GetFdnByOfs(obj, read_start);
+		if (fdn == 0) {
+			dnode = obj->node;
+			type = UFFS_TYPE_FILE;
+		}
+		else {
+			type = UFFS_TYPE_DATA;
+			dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
+			if (dnode == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't get data node in entry!");
+				obj->err = UEUNKNOWN;
+				break;
+			}
+		}
+
+		blockOfs = GetStartOfDataBlock(obj, fdn);
+		page_id = (read_start - blockOfs) / dev->com.pg_data_size;
+
+		if (fdn == 0) {
+			/**
+			 * fdn == 0: this means that the reading is start from the first block,
+			 * since the page 0 is for file attr, so we move to the next page ID.
+			 */
+			page_id++;
+		}
+
+		buf = uffs_BufGetEx(dev, type, dnode, (u16)page_id);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't get buffer when read obj.");
+			obj->err = UEIOERR;
+			break;
+		}
+
+		pageOfs = read_start % dev->com.pg_data_size;
+		if (pageOfs >= buf->data_len) {
+			//uffs_Perror(UFFS_ERR_NOISY, "read data out of page range ?");
+			uffs_BufPut(dev, buf);
+			break;
+		}
+		size = (remain + pageOfs > buf->data_len ? buf->data_len - pageOfs : remain);
+
+		uffs_BufRead(dev, buf, (u8 *)data + len - remain, pageOfs, size);
+		uffs_BufPut(dev, buf);
+
+		remain -= size;
+	}
+
+	obj->pos += (len - remain);
+
+	if (HAVE_BADBLOCK(dev)) 
+		uffs_BadBlockRecover(dev);
+
+	uffs_ObjectDevUnLock(obj);
+
+	return len - remain;
+}
+
+/**
+ * move the file pointer
+ *
+ * \param[in] obj uffs object
+ * \param[in] offset offset from origin
+ * \param[in] origin the origin position, one of:
+ *
+ * \return return the new file pointer position
+ */
+long uffs_SeekObject(uffs_Object *obj, long offset, int origin)
+{
+	if (obj->type == UFFS_TYPE_DIR) {
+		uffs_Perror(UFFS_ERR_NOISY, "Can't seek a dir object!");
+		return 0;
+	}
+
+	uffs_ObjectDevLock(obj);
+
+	switch (origin) {
+		case USEEK_CUR:
+			if (obj->pos + offset > obj->node->u.file.len) {
+				obj->pos = obj->node->u.file.len;
+			}
+			else {
+				obj->pos += offset;
+			}
+			break;
+		case USEEK_SET:
+			if (offset > (long) obj->node->u.file.len) {
+				obj->pos = obj->node->u.file.len;
+			}
+			else {
+				obj->pos = offset;
+			}
+			break;
+		case USEEK_END:
+			if ( offset>0 ) {
+				obj->pos = obj->node->u.file.len;
+			}
+			else if((offset >= 0 ? offset : -offset) > (long) obj->node->u.file.len) {
+				obj->pos = 0;
+			}
+			else {
+				obj->pos = obj->node->u.file.len + offset;
+			}
+			break;
+	}
+
+	uffs_ObjectDevUnLock(obj);
+
+	return (long) obj->pos;
+}
+
+/**
+ * get current file pointer
+ *
+ * \param[in] obj uffs object
+ *
+ * \return return the file pointer position if the obj is valid, return -1 if obj is invalid.
+ */
+int uffs_GetCurOffset(uffs_Object *obj)
+{
+	if (obj) {
+		if (obj->dev && obj->open_succ == U_TRUE)
+			return obj->pos;
+	}
+	return -1;
+}
+
+/**
+ * check whether the file pointer is at the end of file
+ *
+ * \param[in] obj uffs object
+ *
+ * \return return 1 if file pointer is at the end of file, return -1 if error occur, else return 0.
+ */
+int uffs_EndOfFile(uffs_Object *obj)
+{
+	if (obj) {
+		if (obj->dev && obj->type == UFFS_TYPE_FILE && obj->open_succ == U_TRUE) {
+			if (obj->pos >= obj->node->u.file.len) {
+				return 1;
+			}
+			else {
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+static URET do_TruncateInternalWithBlockRecover(uffs_Object *obj, u16 fdn, u32 remain, UBOOL dry_run)
+{
+	uffs_Device *dev = obj->dev;
+	TreeNode *fnode = obj->node;
+	u16 page_id, max_page_id;
+	TreeNode *node;
+	uffs_Buf *buf = NULL;
+	u8 type;
+	u32 block_start;
+	u16 parent, serial;
+	int slot;
+
+	if (fdn == 0) {
+		node = fnode;
+		type = UFFS_TYPE_FILE;
+		max_page_id = obj->head_pages;
+		block_start = 0;
+		parent = node->u.file.parent;
+		serial = node->u.file.serial;
+	}
+	else {
+		node = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
+		if (node == NULL) {
+			obj->err = UEIOERR;
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node when truncate obj");
+			goto ext;
+		}
+		type = UFFS_TYPE_DATA;
+		max_page_id = dev->attr->pages_per_block - 1;
+		block_start = obj->head_pages * dev->com.pg_data_size +  (fdn - 1) * dev->com.pg_data_size * dev->attr->pages_per_block;
+		parent = node->u.data.parent;
+		serial = node->u.data.serial;
+	}
+
+	if (dry_run == U_TRUE) {
+		// checking the buffer. this is the main reason why we need the 'dry run' mode.
+		for (page_id = 0; page_id <= max_page_id; page_id++) {
+			buf = uffs_BufFind(dev, parent, serial, page_id);
+			if (buf) {								//!< ok, the buffer was loaded before ...
+				if (uffs_BufIsFree(buf) == U_FALSE) {
+					obj->err = UEEXIST;
+					break;						//!< and someone is still holding the buffer, can't truncate it !!!
+				}
+			}
+		}
+		buf = NULL;
+		goto ext;
+	}
+	
+	// find the last page after truncate
+	for (page_id = (fdn == 0 ? 1 : 0); page_id <= max_page_id; page_id++) {
+		if (block_start + (page_id + 1) * dev->com.pg_data_size >= remain)
+			break;
+	}
+
+	if (page_id > max_page_id) {
+		obj->err = UEUNKNOWN;
+		uffs_Perror(UFFS_ERR_SERIOUS, "Overflow");
+		goto ext;
+	}
+
+	// flush buffer before performing block recovery
+	uffs_BufFlushGroup(dev, parent, serial);
+
+	// load the last page
+	buf = uffs_BufGetEx(dev, type, node, page_id);
+	if (buf == NULL) {
+		obj->err = UENOMEM;
+		uffs_Perror(UFFS_ERR_SERIOUS, "Can't get buf");
+		goto ext;
+	}
+
+	uffs_BufWrite(dev, buf, NULL, 0, 0); // just make this buf dirty
+
+	// lock the group
+	slot = uffs_BufFindGroupSlot(dev, parent, serial);
+	uffs_BufLockGroup(dev, slot);
+
+	if (remain == 0)
+		buf->data_len = 0;
+	else {
+		remain = (remain % dev->com.pg_data_size);
+		buf->data_len = (remain == 0 ? dev->com.pg_data_size : 0);
+	}
+	buf->ext_mark |= UFFS_BUF_EXT_MARK_TRUNC_TAIL;
+	uffs_BufPut(dev, buf);
+
+	// invalidate the rest page buf
+	page_id++;
+	for (; page_id <= max_page_id; page_id++) {
+		buf = uffs_BufFind(dev, parent, serial, page_id);
+		if (buf)
+			uffs_BufMarkEmpty(dev, buf);
+	}
+
+	// flush dirty buffer immediately, forcing block recovery.
+	uffs_BufFlushGroupEx(dev, parent, serial, U_TRUE);
+
+	// unlock the group
+	uffs_BufUnLockGroup(dev, slot);
+
+ext:
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+/**
+ * truncate an object
+ *
+ * \param[in] obj object to be truncated
+ * \param[in] remain data bytes to be remained in this object
+ *
+ * \return U_SUCC or U_FAIL (error code in obj->err)
+ */
+URET uffs_TruncateObject(uffs_Object *obj, u32 remain)
+{
+	uffs_ObjectDevLock(obj);
+	if (do_TruncateObject(obj, remain, U_TRUE) == U_SUCC)
+		do_TruncateObject(obj, remain, U_FALSE);
+	uffs_ObjectDevUnLock(obj);
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+
+/** truncate obj without lock device */
+static URET do_TruncateObject(uffs_Object *obj, u32 remain, UBOOL dry_run)
+{
+	uffs_Device *dev = obj->dev;
+	TreeNode *fnode = obj->node;
+	u16 fdn;
+	u32 flen;
+	u32 block_start;
+	TreeNode *node;
+	uffs_BlockInfo *bc;
+	uffs_Buf *buf;
+	u16 page;
+
+	if (obj->dev == NULL || obj->open_succ == U_FALSE || fnode == NULL) {
+		obj->err = UEBADF;
+		goto ext;
+	}
+
+	/* can't truncate a dir */
+	/* TODO: delete files under dir ? */
+	if (obj->type == UFFS_TYPE_DIR) {
+		obj->err = UEEXIST;
+		goto ext;
+	}
+
+	if (remain >= fnode->u.file.len) {
+		goto ext;	//!< nothing to do ... 
+	}
+
+	flen = fnode->u.file.len;
+
+	while (flen > remain) {
+		fdn = GetFdnByOfs(obj, flen - 1);
+
+		//uffs_BufFlushGroup(dev, obj->serial, fdn);	//!< flush the buffer
+
+		block_start = GetStartOfDataBlock(obj, fdn);
+		if (remain <= block_start && fdn > 0) {
+			node = uffs_TreeFindDataNode(dev, obj->serial, fdn);
+			if (node == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node when trancate obj.");
+				obj->err = UEIOERR;
+				goto ext;
+			}
+			bc = uffs_BlockInfoGet(dev, node->u.data.block);
+			if (bc == NULL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "can't get block info when trancate obj.");
+				obj->err = UEIOERR;
+				goto ext;
+			}
+
+			for (page = 0; page < dev->attr->pages_per_block; page++) {
+				buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page);
+				if (buf) {								//!< ok, the buffer was loaded before ...
+					if (uffs_BufIsFree(buf) == U_FALSE) {
+						uffs_BlockInfoPut(dev, bc);
+						goto ext;						//!< and someone is still holding the buffer, can't truncate it !!!
+					}
+					else if (dry_run == U_FALSE)
+						uffs_BufMarkEmpty(dev, buf);	//!< discard the buffer
+				}
+			}
+
+			if (dry_run == U_FALSE) {
+				uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+				uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node);
+				uffs_FlashEraseBlock(dev, bc->block);
+				node->u.list.block = bc->block;
+				if (HAVE_BADBLOCK(dev))
+					uffs_BadBlockProcess(dev, node);
+				else
+					uffs_TreeInsertToErasedListTail(dev, node);
+
+				uffs_BlockInfoPut(dev, bc);
+				fnode->u.file.len = block_start;
+			}
+			else {
+				uffs_BlockInfoPut(dev, bc);
+			}
+			flen = block_start;
+		}
+		else {
+			if (do_TruncateInternalWithBlockRecover(obj, fdn, remain, dry_run) == U_SUCC) {
+				if (dry_run == U_FALSE)
+					fnode->u.file.len = remain;
+				flen = remain;
+			}
+		}
+	}
+
+	if (HAVE_BADBLOCK(dev)) 
+		uffs_BadBlockRecover(dev);
+ext:
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+
+}
+
+
+/**
+ * \brief delete uffs object
+ *
+ * \param[in] name full name of object
+ * \param[out] err return error code
+ *
+ * \return U_SUCC if object is deleted successfully. 
+ *	return U_FAIL if error happen, error code is set to *err.
+ */
+URET uffs_DeleteObject(const char * name, int *err)
+{
+	uffs_Object *obj;
+	TreeNode *node;
+	uffs_Device *dev;
+	u16 block;
+	uffs_Buf *buf;
+	URET ret = U_FAIL;
+
+	obj = uffs_GetObject();
+	if (obj == NULL) {
+		if (err)
+			*err = UEMFILE;
+		goto err1;
+	}
+
+	if (uffs_OpenObject(obj, name, UO_RDWR|UO_DIR) == U_FAIL) {
+		if (uffs_OpenObject(obj, name, UO_RDWR) == U_FAIL) {
+			if (err)
+				*err = UENOENT;
+			goto err1;
+		}
+	}
+
+	uffs_TruncateObject(obj, 0);
+
+	uffs_ObjectDevLock(obj);
+	dev = obj->dev;
+
+	if (obj->type == UFFS_TYPE_DIR) 
+	{
+		// if the dir is not empty, can't delete it.
+		node = uffs_TreeFindDirNodeWithParent(dev, obj->serial);
+		if (node != NULL) 
+		{
+			if (err)
+				*err = UEACCES;
+			goto err;  //have sub dirs ?
+		}
+
+		node = uffs_TreeFindFileNodeWithParent(dev, obj->serial);
+		if (node != NULL) 
+		{
+			if (err)
+				*err = UEACCES;
+			goto err;  //have sub files ?
+		}
+	}
+
+	block = GET_BLOCK_FROM_NODE(obj);
+	node = obj->node;
+
+	// before erase the block, we need to take care of the buffer ...
+	uffs_BufFlushAll(dev);
+
+	if (HAVE_BADBLOCK(dev))
+		uffs_BadBlockRecover(dev);
+
+	buf = uffs_BufFind(dev, obj->parent, obj->serial, 0);
+
+	if (buf) {
+		//need to expire this buffer ...
+		if (buf->ref_count != 0) {
+			//there is other obj for this file still in use ?
+			uffs_Perror(UFFS_ERR_NORMAL, "Try to delete object but still have buf referenced.");
+			if (err)
+				*err = UEACCES;
+			goto err;
+		}
+
+		buf->mark = UFFS_BUF_EMPTY; //!< make this buffer expired.
+	}
+
+	//TODO: need to take care of other obj->node ?
+
+	uffs_BreakFromEntry(dev, obj->type, node);
+	uffs_FlashEraseBlock(dev, block);
+	node->u.list.block = block;
+	if (HAVE_BADBLOCK(dev))
+		uffs_BadBlockProcess(dev, node);
+	else
+		uffs_TreeInsertToErasedListTail(dev, node);
+
+	ret = U_SUCC;
+err:
+	uffs_ObjectDevUnLock(obj);
+err1:
+	do_ReleaseObjectResource(obj);
+
+	uffs_PutObject(obj);
+
+	return ret;
+}
+
+/**
+ * Remove object under a new parent, change object name.
+ *
+ * \param[in|out] obj
+ * \param[in] new_parent new parent's serial number
+ * \param[in] new_name new name of the object. if new_name == NULL, keep the old name.
+ * \param[in] name_len new name length.
+ *
+ * \return U_SUCC or U_FAIL (obj->err for the reason)
+ */
+URET uffs_MoveObjectEx(uffs_Object *obj, int new_parent, const char *new_name, int name_len)
+{
+	uffs_Buf *buf;
+	uffs_FileInfo fi;
+	uffs_Device *dev = obj->dev;
+	TreeNode *node = obj->node;
+
+	if (dev == NULL || node == NULL || obj->open_succ != U_TRUE) {
+		obj->err = UEBADF;
+		goto ext;
+	}
+
+	uffs_ObjectDevLock(obj);
+
+	obj->parent = new_parent;
+
+	if (name_len > 0) {
+
+		buf = uffs_BufGetEx(dev, obj->type, node, 0);
+		if (buf == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't get buf when rename!");
+			obj->err = UEIOERR;
+			goto ext_1;
+		}
+
+		memcpy(&fi, buf->data, sizeof(uffs_FileInfo));
+
+		if (new_name[name_len-1] == '/')
+			name_len--;
+
+		memcpy(fi.name, new_name, name_len);
+		fi.name[name_len] = 0;
+		fi.name_len = name_len;
+		fi.last_modify = uffs_GetCurDateTime();
+
+		buf->parent = new_parent;	// !! need to manually change the 'parent' !!
+		uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_FileInfo));
+		uffs_BufPut(dev, buf);
+
+		// !! force a block recover so that all old tag will be expired !!
+		// This is important so we only need to check the first spare when mount UFFS :)
+		uffs_BufFlushGroupEx(dev, obj->parent, obj->serial, U_TRUE);
+
+		obj->name = new_name;
+		obj->name_len = name_len;
+		obj->sum = uffs_MakeSum16(fi.name, fi.name_len);
+	}
+
+	//update the check sum and new parent of tree node
+	if (obj->type == UFFS_TYPE_DIR) {
+		obj->node->u.dir.checksum = obj->sum;
+		obj->node->u.dir.parent = new_parent;
+	}
+	else {
+		obj->node->u.file.checksum = obj->sum;
+		obj->node->u.file.parent = new_parent;
+	}
+
+ext_1:
+	uffs_ObjectDevUnLock(obj);
+ext:
+
+	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
+}
+
+/**
+ * \brief rename(move) file or dir.
+ * \return U_SUCC if success, otherwise return U_FAIL and set error code to *err.
+ * \note rename/move file between different mount point is not allowed.
+ */
+URET uffs_RenameObject(const char *old_name, const char *new_name, int *err)
+{
+	uffs_Object *obj = NULL, *new_obj = NULL;
+	URET ret = U_FAIL;
+	int oflag;
+
+	obj = uffs_GetObject();
+	new_obj = uffs_GetObject();
+
+	if (obj == NULL || new_obj == NULL) {
+		if (err) 
+			*err = UEINVAL;
+		goto ext;
+	}
+
+	oflag = UO_RDONLY;
+	if (uffs_OpenObject(new_obj, new_name, oflag) == U_SUCC) {
+		uffs_CloseObject(new_obj);
+		uffs_Perror(UFFS_ERR_NOISY, "new object already exist!");
+		if (err)
+			*err = UEEXIST;
+		goto ext;
+	}
+	oflag |= UO_DIR;
+	if (uffs_OpenObject(new_obj, new_name, oflag) == U_SUCC) {
+		uffs_CloseObject(new_obj);
+		uffs_Perror(UFFS_ERR_NOISY, "new object already exist!");
+		if (err)
+			*err = UEEXIST;
+		goto ext;
+	}
+
+	if (uffs_ParseObject(new_obj, new_name) != U_SUCC) {
+		uffs_Perror(UFFS_ERR_NOISY, "parse new name fail !");
+		if (err)
+			*err = UENOENT;
+		goto ext;
+	}
+
+	if (new_obj->name_len == 0) {
+		uffs_Perror(UFFS_ERR_NOISY, "invalid new name");
+		if (err)
+			*err = UEINVAL;
+		goto ext;
+	}
+
+	oflag = UO_RDONLY;
+	if (uffs_OpenObject(obj, old_name, oflag) != U_SUCC) {
+		oflag |= UO_DIR;
+		if (uffs_OpenObject(obj, old_name, oflag) != U_SUCC) {
+			uffs_Perror(UFFS_ERR_NOISY, "Can't open old object !");
+			if (err)
+				*err = UEACCES;
+			goto ext;
+		}
+	}
+
+	if (obj->dev != new_obj->dev) {
+		uffs_Perror(UFFS_ERR_NOISY, "Can't move object between different mount point");
+		if (err)
+			*err = UEACCES;
+	}
+	else {
+		ret = uffs_MoveObjectEx(obj, new_obj->parent, new_obj->name, new_obj->name_len);
+		if (ret == U_FAIL && err)
+			*err = obj->err;
+	}
+
+	uffs_CloseObject(obj);
+
+ext:
+	if (obj) uffs_PutObject(obj);
+	if (new_obj) uffs_PutObject(new_obj);
+
+	return ret;
+}
+

+ 144 - 144
components/dfs/filesystems/uffs/src/uffs/uffs_init.c

@@ -1,144 +1,144 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_init.c
- * \brief initialize uffs file system device
- * \author Ricky Zheng, created 12th May, 2005
- */
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_tree.h"
-#include "uffs/uffs_fs.h"
-#include "uffs/uffs_badblock.h"
-#include <string.h>
-
-#define PFX "init: "
-
-URET uffs_InitDevice(uffs_Device *dev)
-{
-	URET ret;
-
-	if (dev->mem.init) {
-		if (dev->mem.init(dev) != U_SUCC) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Init memory allocator fail.");
-			return U_FAIL;
-		}
-	}
-
-	memset(&(dev->st), 0, sizeof(uffs_FlashStat));
-
-	uffs_DeviceInitLock(dev);
-	uffs_BadBlockInit(dev);
-
-	if (uffs_FlashInterfaceInit(dev) != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Can't initialize flash interface !");
-		goto fail;
-	}
-
-	uffs_Perror(UFFS_ERR_NOISY, "init page buf");
-	ret = uffs_BufInit(dev, MAX_PAGE_BUFFERS, MAX_DIRTY_PAGES_IN_A_BLOCK);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_DEAD, "Initialize page buffers fail");
-		goto fail;
-	}
-	uffs_Perror(UFFS_ERR_NOISY, "init block info cache");
-	ret = uffs_BlockInfoInitCache(dev, MAX_CACHED_BLOCK_INFO);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_DEAD, "Initialize block info fail");
-		goto fail;
-	}
-
-	ret = uffs_TreeInit(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "fail to init tree buffers");
-		goto fail;
-	}
-
-	ret = uffs_BuildTree(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "fail to build tree");
-		goto fail;
-	}
-
-	return U_SUCC;
-
-fail:
-	uffs_DeviceReleaseLock(dev);
-
-	return U_FAIL;
-}
-
-URET uffs_ReleaseDevice(uffs_Device *dev)
-{
-	URET ret;
-
-	ret = uffs_BlockInfoReleaseCache(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS,  "fail to release block info.");
-		goto ext;
-	}
-
-	ret = uffs_BufReleaseAll(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS,  "fail to release page buffers");
-		goto ext;
-	}
-
-	ret = uffs_TreeRelease(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
-		goto ext;
-	}
-
-	ret = uffs_FlashInterfaceRelease(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
-		goto ext;
-	}
-
-	if (dev->mem.release)
-		ret = dev->mem.release(dev);
-
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release memory allocator!");
-	}
-
-	uffs_DeviceReleaseLock(dev);
-
-ext:
-	return ret;
-
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_init.c
+ * \brief initialize uffs file system device
+ * \author Ricky Zheng, created 12th May, 2005
+ */
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_tree.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_badblock.h"
+#include <string.h>
+
+#define PFX "init: "
+
+URET uffs_InitDevice(uffs_Device *dev)
+{
+	URET ret;
+
+	if (dev->mem.init) {
+		if (dev->mem.init(dev) != U_SUCC) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "Init memory allocator fail.");
+			return U_FAIL;
+		}
+	}
+
+	memset(&(dev->st), 0, sizeof(uffs_FlashStat));
+
+	uffs_DeviceInitLock(dev);
+	uffs_BadBlockInit(dev);
+
+	if (uffs_FlashInterfaceInit(dev) != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "Can't initialize flash interface !");
+		goto fail;
+	}
+
+	uffs_Perror(UFFS_ERR_NOISY, "init page buf");
+	ret = uffs_BufInit(dev, MAX_PAGE_BUFFERS, MAX_DIRTY_PAGES_IN_A_BLOCK);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_DEAD, "Initialize page buffers fail");
+		goto fail;
+	}
+	uffs_Perror(UFFS_ERR_NOISY, "init block info cache");
+	ret = uffs_BlockInfoInitCache(dev, MAX_CACHED_BLOCK_INFO);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_DEAD, "Initialize block info fail");
+		goto fail;
+	}
+
+	ret = uffs_TreeInit(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "fail to init tree buffers");
+		goto fail;
+	}
+
+	ret = uffs_BuildTree(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "fail to build tree");
+		goto fail;
+	}
+
+	return U_SUCC;
+
+fail:
+	uffs_DeviceReleaseLock(dev);
+
+	return U_FAIL;
+}
+
+URET uffs_ReleaseDevice(uffs_Device *dev)
+{
+	URET ret;
+
+	ret = uffs_BlockInfoReleaseCache(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS,  "fail to release block info.");
+		goto ext;
+	}
+
+	ret = uffs_BufReleaseAll(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS,  "fail to release page buffers");
+		goto ext;
+	}
+
+	ret = uffs_TreeRelease(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
+		goto ext;
+	}
+
+	ret = uffs_FlashInterfaceRelease(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
+		goto ext;
+	}
+
+	if (dev->mem.release)
+		ret = dev->mem.release(dev);
+
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "fail to release memory allocator!");
+	}
+
+	uffs_DeviceReleaseLock(dev);
+
+ext:
+	return ret;
+
+}
+

+ 16 - 872
components/dfs/filesystems/uffs/src/uffs/uffs_mem.c

@@ -3,29 +3,6 @@
   
   Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
 
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
   This exception does not invalidate any other reasons why a work based
   on this file might be covered by the GNU General Public License.
 */
@@ -34,9 +11,9 @@
  * \file uffs_mem.c
  * \brief uffs native memory allocator
  * \author Ricky Zheng, created 23th Feb, 2007
- */
+ */
 
-#include <string.h>
+#include <rtthread.h>
 
 #include "uffs/uffs_types.h"
 #include "uffs/uffs_public.h"
@@ -45,858 +22,25 @@
 
 #define PFX "mem: "
 
-#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
-
-#define HEAP_MAGIC_SIZE	8		/* heap magic size, this block is for memory protection */
-
-
-
-
-/* the 'BEST FIT' arithmetic,
- if not defined, the arithmetic
- will be the 'FIRST FIT' */
-#define K_HEAP_ALLOCK_BEST_FIT
-
-
-/* page size may be: 16,32,64,128... */
-#define ALLOC_PAGE_BIT_OFFSET	5
-#define ALLOC_PAGE_SIZE			(1 << ALLOC_PAGE_BIT_OFFSET)
-#define ALLOC_PAGE_MASK			(ALLOC_PAGE_SIZE - 1)
-#define ALLOC_THRESHOLD			(ALLOC_PAGE_SIZE * 1)
-
-/* magic mummbers */
-#define HEAP_NODE_FREE			0x123455aa
-#define HEAP_NODE_ALLOCED		0xaa551234
-
-#define ALLOC_OFFSET	(sizeof(int) + sizeof(int) + sizeof(void *))
-
-/*  Heap memory node type. */
-typedef struct HeapNodeSt {
-	int	mark;					/*	alloc mark	*/
-    int	size;					/*	Size of this node	*/
-	struct HeapNodeSt *prev_node;	/*	private node	*/
-    struct HeapNodeSt *prev_free;	/*  Link to prev free node */
-    struct HeapNodeSt *next_free;	/*	Link to next free node */
-} HeapNode;
-
-
-
-/*
-		p1	|-----------|
-			|prev_node	|	NULL
-			|mark		|	HEAP_NODE_ALLOCED
-			|size		|	p2 - p1
-			|prev_free	|	alloc to user
-			|next_free	|	not used.
-			|			|
-			|			|
-		p2	|-----------|
-			|prev_node	|	p1
-			|mark		|	HEAP_NODE_FREE
-			|size		|	p3 - p2
-			|prev_free	|	NULL
-			|next_free	|	p5
-			|			|
-			|			|
-		p3	|-----------|
-			|prev_node	|	p2
-			|mark		|	HEAP_NODE_ALLOCED
-			|size		|	p4 - p3
-			|prev_free	|	alloc to user
-			|next_free	|	not used.
-			|			|
-			|			|
-		p4	|-----------|
-			|prev_node	|	p3
-			|mark		|	HEAP_NODE_ALLOCED
-			|size		|	p5 - p4
-			|prev_free	|	alloc to user
-			|next_free	|	not used.
-			|			|
-			|			|
-		p5	|-----------|
-			|prev_node	|	p4
-			|mark		|	HEAP_NODE_FREE
-			|size		|	p6 - p5
-			|prev_free	|	p2
-			|next_free	|	NULL
-			|			|
-			|			|
-		p6	|-----------|
-
-*/
-
-static HeapNode* volatile m_heapFreeList = NULL;
-static HeapNode * m_heapTail = NULL; 
-static u32 m_heap_available = 0;
-static u32 m_min_heap_avaiable = 0x0fffffff;
-static u32 m_kernel_heap_total = 0;
-
-static void HeapDeleteFromFreeList(HeapNode *node);
-static void HeapChainToFreeList(HeapNode *node);
-static void *_k_allock_node(HeapNode *node, int size);
-//static void * _kmalloc_clear(int size);
-static int _kfree(void *block);
-
-/*
- *	Delete one node from free list
- *
- */
-static void HeapDeleteFromFreeList(HeapNode *node)
-{
-	if(node->next_free)
-		node->next_free->prev_free = node->prev_free;
-	if(node->prev_free)
-		node->prev_free->next_free = node->next_free;
-	if(node == m_heapFreeList)
-		m_heapFreeList = node->next_free;
-}
-
-/*
- *	Chain the node to free list
- */
-static void HeapChainToFreeList(HeapNode *node)
-{
-	node->next_free = NULL;
-	node->prev_free = NULL;
-	if(m_heapFreeList == NULL){
-		m_heapFreeList = node;
-		return;
-	}
-	else{
-		m_heapFreeList->prev_free = node;
-		node->next_free = m_heapFreeList;
-		m_heapFreeList = node;
-	}
-}
-
-/*
- * Alloc a block with given node
- * If the node  is larger than the
- * required space plus the space needed for
- * a new node plus a defined threshold, then
- * we split it. The unused portion is put back into
- * the free-list.
- *
- * Attention: Irq is locked when call this routin,
- * so we must unlock irq when return
- */
-static void *_k_allock_node(HeapNode *node, int size)
-{
-	HeapNode *newNode;
-
-	if(node->size >= size + ALLOC_THRESHOLD){
-		/*
-		 * we need to split it 
-		 */
-		newNode = (HeapNode *)((char *)node + size);
-		newNode->size = node->size - size;
-		newNode->mark = HEAP_NODE_FREE;
-		newNode->prev_node = node;
-		node->size = size;
-		/*
-		 *	chain the newNode to free list
-		 */
-		HeapChainToFreeList(newNode);
-				
-		/*
-		 *	fix the next node
-		 */
-		 ((HeapNode *)((char *)newNode + newNode->size))->prev_node = newNode;
-	}
-		
-	/*
-	 *	allock this block
-	 */
-	node->mark = HEAP_NODE_ALLOCED;
-
-	/*
-	 *	delete the node from free list
-	 */
-	HeapDeleteFromFreeList(node);
-
-	m_heap_available -= node->size;
-	if(m_min_heap_avaiable > m_heap_available)
-		m_min_heap_avaiable = m_heap_available;
-	
-	uffs_CriticalExit();	/* exit critical */
-	
-	return (void *)((char *)node + ALLOC_OFFSET);
-}
-
-/*
- * Allocate a block from heap memory.
- *
- * This functions allocates a memory block of the specified
- * size and returns a pointer to that block.
- *
- * The actual size of the allocated block is larger than the
- * requested size because of space required for maintenance
- * information. This additional information is invisible to
- * the application.
- *
- * The routine looks for the smallest block that will meet
- * the required size and releases it to the caller. If the
- * block being requested is usefully smaller than the smallest
- * free block then the block from which the request is being
- * met is split in two. The unused portion is put back into
- * the free-list.
- *
- * The contents of the allocated block is unspecified.
- * To allocate a block with all bytes set to zero use
- * KHeapAllocClear().
- *
- * \note Interrupts are automatically enabled, when this
- *       function returns.
- *
- * \param size Size of the requested memory block.
- *
- * \return Pointer to the allocated memory block if the
- *         function is successful or NULL if the requested
- *         amount of memory is not m_heap_available.
- */
-static void *_kmalloc(int size)
-{
-	HeapNode *node;
-#if defined(K_HEAP_ALLOCK_BEST_FIT)
-	HeapNode *fit;
-#endif
-	if(size <= 0)
-		return NULL;	/* size is not fit */
-		
-	/*
-	 *	adjust size
-	 */
-	size += ALLOC_OFFSET;
-	if(size & ALLOC_PAGE_MASK){
-		size += ALLOC_PAGE_SIZE;
-		size &= ~ALLOC_PAGE_MASK;
-	}
-
-	uffs_CriticalEnter();	/* enter critical */
-	
-	node = m_heapFreeList;
-	
-#if defined(K_HEAP_ALLOCK_BEST_FIT)
-    /*
-     * Walk through the linked list of free nodes and find the best fit.
-     */
-	fit = NULL;
-	while(node){
-        /*
-         * Found a note that fits?
-         */
-		if(node->size >= size){
-            /*
-             * If it's an exact match, we don't
-             * search any further.
-             */
-			if(node->size == size){
-				fit = node;
-				break;
-			}
-			/*
-			 *	We search most fit one
-			 */
-			if(fit){
-				if(node->size < fit->size)
-					fit = node;
-			}
-			else
-				fit = node;
-		}
-		node = node->next_free;
-	}
-	
-	if(fit){
-		if(fit->size >= size)
-			return _k_allock_node(fit, size);
-	}
-#else
-	while(node){
-		if(node->size >= size)
-			return _k_allock_node(node, size);
-		node = node->next_free;
-	}
-#endif
-
-	uffs_CriticalExit();	/* exit critical */
-	
-	return NULL;	/*	not found available block	*/
-
-}
-
-#if 0
-/* Allocates an array in memory with elements initialized to 0 */
-static void *_kcalloc(int num, int size)
-{
-	return _kmalloc_clear(num * size);
-}
-#endif
-
-/* Realloc memory.
- * if the size of memblock is small then the new required size, 
- * alloc a new block memory, and copy the contents from the old one,
- * and free the old block.
- * if the size is zero, free the old block, and return NULL. <2004.5.8>
- * if the size of origin block is larger then the new required size,
- * then: 
- *   if the gap is larger then ALLOC_PAGE_SIZE, split the node, and return
- *		the leav memory back to free list.
- *   if the gap is less then ALLOC_PAGE_SIZE, just return current block.
- * If the given block parameter is NULL, _krealloc behaves the same as _kmalloc.
- */
-static void *_krealloc(void *block, int size)
-{
-	HeapNode *node;
-	HeapNode *newNode;
-	void *p;	/* return pointer */
-	int old_data_size; /* old block data size */
-
-	if(block == NULL){
-		return _kmalloc(size);
-	}
-	
-	if(size == 0) {
-		_kfree(block);
-		return NULL;
-	}
-
-	uffs_CriticalEnter();	/* enter critical */
-	
-	node = (HeapNode *)((char *)block - ALLOC_OFFSET);
-	old_data_size = node->size - ALLOC_OFFSET;
-	if(node->mark != (int)HEAP_NODE_ALLOCED || old_data_size <= 0) {
-		uffs_CriticalExit(); /* exit critical */
-		return NULL;	/*!!!! at this moment, the heap 
-						managment info must be damaged !!!!!*/
-	}
-
-	if(old_data_size < size) {
-		/* new size is larger then origin block, so need alloc new block */
-		p = _kmalloc(size);
-		if(!p) {
-			uffs_CriticalExit(); /* exit critical */
-			return NULL;		/* can't alloc a new block memory, fail... */
-		}
-
-		/* alloc a new block, and copy contents from origin block,
-		 * and free it finally.
-		 */
-		memcpy(p, block, old_data_size);
-		_kfree(block);
-		uffs_CriticalExit(); /* exit critical */
-		return p;
-	}
-	else {
-		/* adjust size */
-		size += ALLOC_OFFSET;
-		if(size & ALLOC_PAGE_MASK) {
-			size += ALLOC_PAGE_SIZE;
-			size &= ~ALLOC_PAGE_MASK;
-		}
-
-		if(node->size - size < ALLOC_PAGE_SIZE) {
-			/* the remain memory is too small, so just skip it */
-			uffs_CriticalExit(); /* exit critical */
-			return block;
-		}
-		else {
-			/* the remain memory is large enough to be splited */
-			/* we generate a new 'alloced' node there */
-			newNode = (HeapNode *)((char *)node + size);
-			newNode->prev_node = node;
-			newNode->mark = HEAP_NODE_ALLOCED;
-			newNode->size = node->size - size;
-
-			/* split into two node now */
-			((HeapNode *)((char *)node + node->size))->prev_node = newNode;
-			node->size = size;
-
-			/* put the newNode into free list */
-			_kfree((void *)((char *)newNode + ALLOC_OFFSET)); 
-
-			uffs_CriticalExit(); /* exit critical */
-			return block;
-		}
-	}
-}
-
-#if 0
-static void * _kmalloc_clear(int size)
-{
-	void *p;
-	
-	p = _kmalloc(size);
-	if(p)
-		memset(p, 0, size);
-	return p;
-}
-#endif
-
-/*!
- * \brief Return a block to heap memory.
- *
- * An application calls this function, when a previously
- * allocated memory block is no longer needed.
- *
- * The heap manager checks, if the released block adjoins any
- * other free regions. If it does, then the adjacent free regions
- * are joined together to form one larger region.
- *
- * \note Interrupts are automatically enabled, when this
- *       function returns.
- *
- * \param block Points to a memory block previously allocated
- *              through a call to _kmalloc().
- *
- * \return 0 on success, -1 if the caller tried to free
- *         a block which had been previously released.
- */
-static int _kfree(void *block)
-{
-	HeapNode *node;
-	HeapNode *prev;
-	HeapNode *next;
-	if (block == NULL) {
-		return -1;	//the pointer of the memory is invalid.
-	}
-	uffs_CriticalEnter();	/* enter critical */
-	
-	node = (HeapNode *)((char *)block - ALLOC_OFFSET);
-	if(node->mark != (int)HEAP_NODE_ALLOCED || node->size <= ALLOC_OFFSET) {
-		uffs_CriticalExit();/* exit critical */
-		return -1;	/*!!!! at this point, the heap 
-						management info must be damaged !!!!!*/
-	}
-	m_heap_available += node->size;
-	
-	prev = node->prev_node;
-	next = (HeapNode *)((char *)node + node->size);
-
-	if(prev->mark == HEAP_NODE_FREE){
-        /*
-         * If there' s a free node in front of us, merge it.
-         */
-		prev->size += node->size;
-		next->prev_node = prev;
-		HeapDeleteFromFreeList(prev);
-		node = prev;
-	}
-
-	if(next->mark == HEAP_NODE_FREE){
-        /*
-         * If there' s a free node following us, merge it.
-         */
-		node->size += next->size;
-		((HeapNode *)((char *)next + next->size))->prev_node = node;
-		HeapDeleteFromFreeList(next);
-	}
-
-	/*
-	 *	now, we just chain the node to free list head.
-	 */
-	node->mark = HEAP_NODE_FREE;
-	HeapChainToFreeList(node);
-	uffs_CriticalExit();	/* exit critical */
-	
-	return 0;
-}
-
-
-/*!
- * \brief
- * Add a new memory region to the free heap.
- *
- * This function is called during
- * initialization.
- *
- * Applications typically do not call this function.
- *
- * \param addr Start address of the memory region.
- * \param size Number of bytes of the memory region.
- */
-void uffs_MemInitHeap(void *addr, int size)
-{
-	HeapNode *np;
-	
-	
-	if(!((long)addr & 3)){
-		addr = (void *)(((char *)addr) + 4);
-		addr = (void *)(((long)addr) & ~3);
-	}
-	size &= ~ALLOC_PAGE_MASK;
-	if(size < ALLOC_PAGE_SIZE * 3) return;
-
-	uffs_CriticalEnter();
-	
-	/* pre alloc header node, size is ALLOC_PAGE_SIZE */
-	np = (HeapNode *)addr;
-	np->size = ALLOC_PAGE_SIZE;
-	np->mark = HEAP_NODE_ALLOCED;
-	np->prev_node = NULL;
-
-	/* pre alloc tail node, size is -1 */
-    np = (HeapNode *)((char *)addr + size - ALLOC_PAGE_SIZE);
-	np->mark = HEAP_NODE_ALLOCED;
-	np->size = -1;
-	np->prev_node = (HeapNode *)((char *)addr + ALLOC_PAGE_SIZE);
-	m_heapTail = np;
-
-	/* Free list head */
-    np = (HeapNode *)((char *)addr + ALLOC_PAGE_SIZE);
-    np->mark = HEAP_NODE_FREE;
-    np->prev_node = (HeapNode *)addr;
-    np->size = size - 2 * ALLOC_PAGE_SIZE;
-    np->next_free = NULL;
-    np->prev_free = NULL;
-	m_heapFreeList = np;
-	m_heap_available = np->size;
-	m_min_heap_avaiable = m_heap_available;
-	
-	m_kernel_heap_total += size;
-
-	uffs_CriticalExit();
-}
-
-/******************************************************************************************/
-
-
-static void *__umalloc(uffs_MemAllocator *mem, unsigned int size, HeapHashTable * hash_tbl);
-static void *__ucalloc(uffs_MemAllocator *mem, unsigned int num, unsigned int size, HeapHashTable *hash_tbl);
-static void *__urealloc(uffs_MemAllocator *mem, void *block, unsigned int size, HeapHashTable *hash_tbl);
-static int __ufree(uffs_MemAllocator *mem, void *p, HeapHashTable * hash_tbl);
-
-
-/* release all alloced memory from hash table,
- * return alloced pointer nummber.
- */
-static int ReleaseHeap(uffs_MemAllocator *mem, HeapHashTable *hash_tbl)
-{
-	int i;
-	int count = 0;
-	HeapMm volatile * node;
-
-	if (hash_tbl == NULL) 
-		return -1;
-	for (i = 0; i < HEAP_HASH_SIZE; i++){
-		while ((node = hash_tbl[i]) != NULL){
-			__ufree(mem, node->p, hash_tbl);
-			count++;
-		}
-	}
-	_kfree(hash_tbl);
-
-	return count;
-}
-
-static void *uffs_malloc(struct uffs_DeviceSt *dev, unsigned int size)
-{
-	HeapHashTable * hash_tbl;
-
-	if ((int)size < 0)
-		return NULL;
-
-	hash_tbl = dev->mem.tbl;
-	if (hash_tbl) {
-		return __umalloc(&dev->mem, size, hash_tbl);
-	}
-	else{
-		return NULL;
-	}
-}
-
-
-/* alloc one block with given size, return the block pointer */
-static void *__umalloc(uffs_MemAllocator *mem, unsigned int size, HeapHashTable *hash_tbl)
-{
-	void *p;
-	HeapMm *node;
-	int idx;
-	
-	/* calling kernel routin allocate bigger size memory block */
-	p = _kmalloc(HEAP_MAGIC_SIZE + size + HEAP_MAGIC_SIZE);
-	
-	if (p) {
-		node = (HeapMm *)_kmalloc(sizeof(HeapMm));
-		if (node == NULL) {
-			_kfree(p);
-			return NULL;
-		}
-		p = (void *)((char *)p + HEAP_MAGIC_SIZE);	/* adjust pointer first */
-		node->p = p;
-		node->size = size;
-		mem->count += size;
-
-		if (mem->maxused < mem->count) 
-			mem->maxused = mem->count;
-
-		node->task_id = uffs_OSGetTaskId();	/* get task id */
-		
-		uffs_CriticalEnter();
-		
-		/* insert node to hash table */
-		idx = GET_HASH_INDEX(p);
-		node->next = hash_tbl[idx];
-		hash_tbl[idx] = node;
-		
-		uffs_CriticalExit();
-
-		return p;	/* ok, return the pointer */
-	}
-	return NULL;
-}
-
-/* Allocates an array in memory with elements initialized to 0 */
-static void *__ucalloc(uffs_MemAllocator *mem, unsigned int num, unsigned int size, HeapHashTable *hash_tbl)
-{
-	return __umalloc(mem, num * size, hash_tbl);
-}
-
-
-/* realloc one block with given size, return the block pointer */
-static void *__urealloc(uffs_MemAllocator *mem, void *block, unsigned int size, HeapHashTable *hash_tbl)
-{
-	void *p, *pNew;
-	HeapMm *prev, *node;
-	int idx;
-
-	if (block == NULL) {
-		return __umalloc(mem, size, hash_tbl);
-	}
-
-	if (size == 0) {
-		__ufree(mem, block, hash_tbl);
-		return NULL;
-	}
-
-	/* calculate hash idx */
-	idx = GET_HASH_INDEX(block);
-
-	/* check whether block pointer is alloc from this heap... */
-	uffs_CriticalEnter();
-	node = hash_tbl[idx];
-	prev = NULL;
-
-	while (node){
-		if (node->p == block) {
-			break; /* got it! */
-		}
-		prev = node;
-		node = node->next;	/* search for next node */
-	}
-
-	if (!node) {
-		/* not my duty :-) */
-		uffs_CriticalExit();
-		return NULL;
-	}
-
-	/* ok, begin call kernel API to realloc memory */
-
-	p = (void *)((char *)block - HEAP_MAGIC_SIZE);	/* get real pointer which kernel need */
-	pNew = _krealloc(p, HEAP_MAGIC_SIZE + size + HEAP_MAGIC_SIZE);
-
-	if (pNew == NULL) {	/* realloc fail */
-		uffs_CriticalExit();
-		return NULL;
-	}
-
-	if (pNew == p) {
-		/* new block is the same as the old block */
-		uffs_CriticalExit();
-		return block;
-	}
-
-	/* new block is difference with old block, we need to change hash table ... */
-	if (prev){
-		/* prev is not the first */
-		prev->next = node->next;
-	}
-	else{
-		/* this node is the first, so.. */
-		hash_tbl[idx] = node->next;
-	}
-	uffs_CriticalExit();
-
-	node->p = (void *)((char *)pNew + HEAP_MAGIC_SIZE);
-	node->size = size;
-	node->task_id = uffs_OSGetTaskId();
-
-	/* insert node into hash table */
-	idx = GET_HASH_INDEX(node->p);
-	uffs_CriticalEnter();
-	node->next = hash_tbl[idx];
-	hash_tbl[idx] = node;
-	uffs_CriticalExit();
-
-	return node->p;
-	
-}
-
-
-/* free the block, if the pointer(parameter 'p') is 
- * not valid(allocated by this allocate system) or error occur, return -1,
- * else return 0
- */
-static int __ufree(uffs_MemAllocator *mem, void *p, HeapHashTable *hash_tbl)
-{
-	HeapMm *node, *prev;
-	
-	if (p) {	/* check the pointer */
-		uffs_CriticalEnter();
-		node = hash_tbl[GET_HASH_INDEX(p)];
-		prev = NULL;
-		while (node) {
-			if (node->p == p) {
-				/* we find the node, so begin to release */
-				if (prev) {
-					/* this node is not the first */
-					prev->next = node->next;
-				}
-				else {
-					/* this node is the first node of hash channel */
-					hash_tbl[GET_HASH_INDEX(p)] = node->next;
-				}
-
-				mem->count -= node->size;
-				
-				uffs_CriticalExit();
-				if (_kfree(node) == -1)	/* calling kernel routine release node */
-					return -1;			/* fail, return -1 */
-				
-				/* calling kernel routine and return */
-				return _kfree((void *)((char *)p - HEAP_MAGIC_SIZE)); 
-			}
-			prev = node;
-			node = node->next;	/* search for next node */
-		}
-		uffs_CriticalExit();
-	}
-
-	return -1;
-}
-
-static URET uffs_free(struct uffs_DeviceSt *dev, void *block)
-{
-	HeapHashTable *hash_tbl;
-	hash_tbl = dev->mem.tbl;
-
-	if (hash_tbl) {
-		if (__ufree(&dev->mem, block, hash_tbl) < 0) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Try to free unmanaged memory ?");
-			return U_FAIL;
-		}
-	}
-
-	return U_SUCC;
-}
-
-URET uffs_MemInitNativeAllocator(uffs_Device *dev)
-{
-	uffs_MemAllocator *mem = &dev->mem;
-
-	memset(mem->tbl, 0, sizeof(mem->tbl));
-	mem->malloc = uffs_malloc;
-	mem->free = uffs_free;
-	mem->blockinfo_pool_size = 0;
-	mem->pagebuf_pool_size = 0;
-	mem->tree_nodes_pool_size = 0;
-
-	return U_SUCC;
-}
-
-
-URET uffs_MemReleaseNativeAllocator(uffs_Device *dev)
-{
-	int count;
-	URET ret = U_SUCC;
-
-	if (dev) {
-		count = ReleaseHeap(&dev->mem, dev->mem.tbl);
-		if (count < 0) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "Release native memory allocator fail!");
-			ret = U_FAIL;
-		}
-		else if (count > 0) {
-			uffs_Perror(UFFS_ERR_NORMAL, "Find %d block memory leak!", count);
-		}
-	}
-
-	return ret;
-}
-
-/**
- * \brief Setup the memory allocator to native memory allocator
- *
- * \param allocator memory allocator to be setup
- */
-void uffs_MemSetupNativeAllocator(uffs_MemAllocator *allocator)
-{
-	memset(allocator, 0, sizeof(uffs_MemAllocator));
-	allocator->init = uffs_MemInitNativeAllocator;
-	allocator->release = uffs_MemReleaseNativeAllocator;
-}
-
-#endif //CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
-
-#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
-#include <malloc.h>
-static void * sys_malloc(struct uffs_DeviceSt *dev, unsigned int size)
-{
-	uffs_Perror(UFFS_ERR_NORMAL, "system memory alloc %d bytes", size);
-	return malloc(size);
-}
-
-static URET sys_free(struct uffs_DeviceSt *dev, void *p)
-{
-	free(p);
-	return U_SUCC;
-}
+#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
+#include <rtthread.h>
+
+void* rt_malloc_link(struct uffs_DeviceSt *dev, unsigned int size)
+{
+	return rt_malloc(size);
+}
+URET rt_free_link(struct uffs_DeviceSt *dev, void *p)
+{
+	rt_free(p);
+	return 0;
+}
 
 void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator)
 {
-	allocator->malloc = sys_malloc;
-	allocator->free = sys_free;
-}
-#endif //CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR
-
-#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
-static void * static_malloc(struct uffs_DeviceSt *dev, unsigned int size)
-{
-	struct uffs_memAllocatorSt *mem = &dev->mem;
-	void *p = NULL;
-
-	size += (size % sizeof(long) ? sizeof(long) - (size % sizeof(long)) : 0);
-
-	if (mem->buf_size - mem->pos < (int)size) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Memory alloc failed! (alloc %d, free %d)", size, mem->buf_size - mem->pos);
-	}
-	else {
-		p = mem->buf_start + mem->pos;
-		mem->pos += size;
-		uffs_Perror(UFFS_ERR_NOISY, "0x%p: Allocated %d, free %d", p, size, mem->buf_size - mem->pos);
-	}
-
-	return p;
-}
-
-void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size)
-{
-	allocator->buf_start = (unsigned char *)pool;
-	allocator->buf_size = size;
-	allocator->pos = 0;
-	allocator->malloc = static_malloc;
-	allocator->free = NULL;  //never free memory for static memory allocator
-
-	uffs_Perror(UFFS_ERR_NOISY, "System static memory: %d bytes", allocator->buf_size);
-	
+	allocator->malloc = rt_malloc_link;
+	allocator->free = rt_free_link;
 }
-
 #endif
 
 
 
-
-
-

+ 250 - 247
components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c

@@ -1,247 +1,250 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_mtb.c
- * \brief mount table operations
- * \author Ricky Zheng, created 11th July, 2009
- */
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_tree.h"
-#include "uffs/uffs_mtb.h"
-#include "uffs/uffs_fd.h"
-#include <string.h>
-
-#define PFX "mtb:  "
-
-static struct uffs_MountTableEntrySt *g_mtb_head = NULL;
-
-uffs_MountTable * uffs_GetMountTable(void)
-{
-	return g_mtb_head;
-}
-
-int uffs_RegisterMountTable(uffs_MountTable *mtab)
-{
-	uffs_MountTable *work = g_mtb_head;
-
-	if (mtab == NULL) 
-		return -1;
-
-	if (work == NULL) {
-		g_mtb_head = mtab;
-		return 0;
-	}
-
-	while (work) {
-		if (mtab == work) {
-			/* already registered */
-			return 0;
-		}
-		if (work->next == NULL) {
-			work->next = mtab;
-			mtab->next = NULL;
-			return 0;
-		}
-		work = work->next;
-	}
-
-	return -1;
-}
-
-
-URET uffs_InitMountTable(void)
-{
-	struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
-	struct uffs_MountTableEntrySt *work;
-	int dev_num = 0;
-
-	for (work = tbl; work; work = work->next) {
-		uffs_Perror(UFFS_ERR_NOISY, "init device for mount point %s ...", work->mount);
-		if (work->dev->Init(work->dev) == U_FAIL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "init device for mount point %s fail", work->mount);
-			return U_FAIL;
-		}
-
-		work->dev->par.start = work->start_block;
-		if (work->end_block < 0) {
-			work->dev->par.end = work->dev->attr->total_blocks + work->end_block;
-		}
-		else {
-			work->dev->par.end = work->end_block;
-		}
-		uffs_Perror(UFFS_ERR_NOISY, "mount partiton: %d,%d",
-			work->dev->par.start, work->dev->par.end);
-
-		if (uffs_InitDevice(work->dev) != U_SUCC) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "init device fail !");
-			return U_FAIL;
-		}
-		work->dev->dev_num = dev_num++;
-	}
-
-	if (uffs_InitObjectBuf() == U_SUCC) {
-		if (uffs_InitDirEntryBuf() == U_SUCC) {
-			return U_SUCC;
-		}
-	}
-
-	return U_FAIL;
-}
-
-URET uffs_ReleaseMountTable(void)
-{
-	struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
-	struct uffs_MountTableEntrySt *work;
-
-	for (work = tbl; work; work = work->next) {
-		uffs_ReleaseDevice(work->dev);
-		work->dev->Release(work->dev);
-	}
-
-	if (uffs_ReleaseObjectBuf() == U_SUCC) {
-		if (uffs_ReleaseDirEntryBuf() == U_SUCC) {
-			return U_SUCC;
-		}
-	}
-
-	return U_FAIL;
-}
-
-
-
-/**
- * find the matched mount point from a given full absolute path.
- *
- * \param[in] path full path
- * \return the length of mount point.
- */
-int uffs_GetMatchedMountPointSize(const char *path)
-{
-	int pos;
-	uffs_Device *dev;
-
-	if (path[0] != '/')
-		return 0;
-
-	pos = strlen(path);
-
-	while (pos > 0) {
-		if ((dev = uffs_GetDeviceFromMountPointEx(path, pos)) != NULL ) {
-			uffs_PutDevice(dev);
-			return pos;
-		}
-		else {
-			if (path[pos-1] == '/') 
-				pos--;
-			//back forward search the next '/'
-			for (; pos > 0 && path[pos-1] != '/'; pos--)
-				;
-		}
-	}
-
-	return pos;
-}
-
-/**
- * get device from mount point.
- *
- * \param[in] mount mount point name.
- * \return NULL if mount point is not found.
- */
-uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount)
-{
-	struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
-
-	while (devTab) {
-		if (strcmp(mount, devTab->mount) == 0) {
-			devTab->dev->ref_count++;
-			return devTab->dev;
-		}
-		devTab = devTab->next;
-	}
-
-	return NULL;
-}
-
-/**
- * get device from mount point.
- *
- * \param[in] mount mount point name.
- * \param[in] len mount point name length.
- * \return NULL if mount point is not found.
- */
-uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len)
-{
-	struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
-
-	while (devTab) {
-		if (strlen(devTab->mount) == len && strncmp(mount, devTab->mount, len) == 0) {
-			devTab->dev->ref_count++;
-			return devTab->dev;
-		}
-		devTab = devTab->next;
-	}
-
-	return NULL;
-}
-
-
-/**
- * return mount point from device
- *
- * \param[in] dev uffs device
- * \return NULL if mount point is not found, otherwise return mount point name in mount table.
- */
-const char * uffs_GetDeviceMountPoint(uffs_Device *dev)
-{
-	struct uffs_MountTableEntrySt * devTab = uffs_GetMountTable();
-
-	while (devTab) {
-		if (devTab->dev == dev) {
-			return devTab->mount;
-		}
-		devTab = devTab->next;
-	}
-
-	return NULL;	
-}
-
-void uffs_PutDevice(uffs_Device *dev)
-{
-	dev->ref_count--;
-}
-
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_mtb.c
+ * \brief mount table operations
+ * \author Ricky Zheng, created 11th July, 2009
+ */
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_tree.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_fd.h"
+#include <string.h>
+
+#define PFX "mtb:  "
+
+static struct uffs_MountTableEntrySt *g_mtb_head = NULL;
+
+uffs_MountTable * uffs_GetMountTable(void)
+{
+	return g_mtb_head;
+}
+
+int uffs_RegisterMountTable(uffs_MountTable *mtab)
+{
+	uffs_MountTable *work = g_mtb_head;
+
+	if (mtab == NULL) 
+		return -1;
+
+	if (work == NULL) {
+		g_mtb_head = mtab;
+		return 0;
+	}
+
+	while (work) {
+		if (mtab == work) {
+			/* already registered */
+			return 0;
+		}
+		if (work->next == NULL) {
+			work->next = mtab;
+			mtab->next = NULL;
+			return 0;
+		}
+		work = work->next;
+	}
+
+	return -1;
+}
+
+
+URET uffs_InitMountTable(void)
+{
+	struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
+	struct uffs_MountTableEntrySt *work;
+	int dev_num = 0;
+
+	for (work = tbl; work; work = work->next) {
+		uffs_Perror(UFFS_ERR_NOISY, "init device for mount point %s ...", work->mount);
+		if (work->dev->Init(work->dev) == U_FAIL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "init device for mount point %s fail", work->mount);
+			return U_FAIL;
+		}
+
+		work->dev->par.start = work->start_block;
+		if (work->end_block < 0) 
+		{
+			work->dev->par.end = work->dev->attr->total_blocks + work->end_block;
+		}
+		else 
+		{
+			work->dev->par.end = work->end_block;
+		}
+		uffs_Perror(UFFS_ERR_NOISY, "mount partiton: %d,%d",
+			work->dev->par.start, work->dev->par.end);
+
+		if (uffs_InitDevice(work->dev) != U_SUCC) 
+		{
+			uffs_Perror(UFFS_ERR_SERIOUS, "init device fail !");
+			return U_FAIL;
+		}
+		work->dev->dev_num = dev_num++;
+	}
+
+	if (uffs_InitObjectBuf() == U_SUCC) {
+		if (uffs_InitDirEntryBuf() == U_SUCC) {
+			return U_SUCC;
+		}
+	}
+
+	return U_FAIL;
+}
+
+URET uffs_ReleaseMountTable(void)
+{
+	struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
+	struct uffs_MountTableEntrySt *work;
+
+	for (work = tbl; work; work = work->next) {
+		uffs_ReleaseDevice(work->dev);
+		work->dev->Release(work->dev);
+	}
+
+	if (uffs_ReleaseObjectBuf() == U_SUCC) {
+		if (uffs_ReleaseDirEntryBuf() == U_SUCC) {
+			return U_SUCC;
+		}
+	}
+
+	return U_FAIL;
+}
+
+
+
+/**
+ * find the matched mount point from a given full absolute path.
+ *
+ * \param[in] path full path
+ * \return the length of mount point.
+ */
+int uffs_GetMatchedMountPointSize(const char *path)
+{
+	int pos;
+	uffs_Device *dev;
+
+	if (path[0] != '/')
+		return 0;
+
+	pos = strlen(path);
+
+	while (pos > 0) {
+		if ((dev = uffs_GetDeviceFromMountPointEx(path, pos)) != NULL ) {
+			uffs_PutDevice(dev);
+			return pos;
+		}
+		else {
+			if (path[pos-1] == '/') 
+				pos--;
+			//back forward search the next '/'
+			for (; pos > 0 && path[pos-1] != '/'; pos--)
+				;
+		}
+	}
+
+	return pos;
+}
+
+/**
+ * get device from mount point.
+ *
+ * \param[in] mount mount point name.
+ * \return NULL if mount point is not found.
+ */
+uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount)
+{
+	struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
+
+	while (devTab) {
+		if (strcmp(mount, devTab->mount) == 0) {
+			devTab->dev->ref_count++;
+			return devTab->dev;
+		}
+		devTab = devTab->next;
+	}
+
+	return NULL;
+}
+
+/**
+ * get device from mount point.
+ *
+ * \param[in] mount mount point name.
+ * \param[in] len mount point name length.
+ * \return NULL if mount point is not found.
+ */
+uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len)
+{
+	struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
+
+	while (devTab) {
+		if (strlen(devTab->mount) == len && strncmp(mount, devTab->mount, len) == 0) {
+			devTab->dev->ref_count++;
+			return devTab->dev;
+		}
+		devTab = devTab->next;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * return mount point from device
+ *
+ * \param[in] dev uffs device
+ * \return NULL if mount point is not found, otherwise return mount point name in mount table.
+ */
+const char * uffs_GetDeviceMountPoint(uffs_Device *dev)
+{
+	struct uffs_MountTableEntrySt * devTab = uffs_GetMountTable();
+
+	while (devTab) {
+		if (devTab->dev == dev) {
+			return devTab->mount;
+		}
+		devTab = devTab->next;
+	}
+
+	return NULL;	
+}
+
+void uffs_PutDevice(uffs_Device *dev)
+{
+	dev->ref_count--;
+}
+
+

+ 343 - 343
components/dfs/filesystems/uffs/src/uffs/uffs_pool.c

@@ -1,343 +1,343 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/** 
- * \file uffs_pool.c
- * \brief Fast fixed size memory pool management.
- * \author Ricky Zheng, Simon Kallweit
- */
- 
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_pool.h"
-
-/*
-
-	usage:
-
-	#define BUF_SIZE	32
-	#define NUM_BUFS	1024
-
-	static int pool_mem[NUM_BUFS * BUF_SIZE / sizeof(int)];
-	static uffs_Pool pool;
-
-	uffs_PoolInit(&pool, pool_mem, sizeof(pool_mem), BUF_SIZE, NUM_BUFS);
-
-	void * p;
-	p = uffs_PoolGet(&pool);
-	...
-	uffs_PoolPut(p, &pool);
-
-	notice:
-
-	uffs_PoolInit will assert when NUM_BUFS is not at least 1, or BUF_SIZE is
-	not	aligned to the platforms pointer size.
-
-*/
-
-
-/**
- * \brief Initializes the memory pool.
- * \param[in] pool memory pool
- * \param[in] mem pool memory
- * \param[in] mem_size size of pool memory
- * \param[in] buf_size size of a single buffer
- * \param[in] num_bufs number of buffers
- * \return Returns U_SUCC if successful.
- */
-URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs)
-{
-	unsigned int i;
-	uffs_PoolEntry *e1, *e2;
-
-	uffs_Assert(pool, "pool missing");
-	uffs_Assert(mem, "pool memory missing");
-	uffs_Assert(num_bufs > 0, "not enough buffers");
-	uffs_Assert(buf_size % sizeof(void *) == 0, "buffer size not aligned to pointer size");
-	uffs_Assert(mem_size == num_bufs * buf_size, "pool memory size is wrong");
-
-	pool->mem = (u8 *)mem;
-	pool->buf_size = buf_size;
-	pool->num_bufs = num_bufs;
-	pool->sem = uffs_SemCreate(1);
-	
-	uffs_SemWait(pool->sem);
-
-	// Initialize the free_list
-	e1 = e2 = pool->free_list = (uffs_PoolEntry *) pool->mem;
-	for (i = 1; i < pool->num_bufs; i++) {
-		e2 = (uffs_PoolEntry *) (pool->mem + i * pool->buf_size);
-		e1->next = e2;
-		e1 = e2;
-	}
-	e2->next = NULL;
-	
-	uffs_SemSignal(pool->sem);
-
-	return U_SUCC;
-}
-
-/**
- * \brief verify pointer validity aganist memory pool
- * \return U_TRUE if valid, U_FALSE if invalid.
- */
-UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p)
-{
-	return  p &&
-			(u8 *)p >= pool->mem &&
-			(u8 *)p < pool->mem + (pool->buf_size * pool->num_bufs) &&
-			(((u8 *)p - pool->mem) % pool->buf_size) == 0	? U_TRUE : U_FALSE;
-}
-
-/**
- * \brief Releases the memory pool.
- * \param[in] pool memory pool
- * \return Returns U_SUCC if successful.
- */
-URET uffs_PoolRelease(uffs_Pool *pool)
-{
-	uffs_Assert(pool, "pool missing");
-	
-	uffs_SemDelete(pool->sem);
-	pool->sem = 0;
-
-	return U_SUCC;
-}
-
-/**
- * \brief Get a buffer from the memory pool.
- * \param[in] pool memory pool
- * \return Returns a pointer to the buffer or NULL if none is available.
- */
-void *uffs_PoolGet(uffs_Pool *pool)
-{
-	uffs_PoolEntry *e;
-
-	uffs_Assert(pool, "pool missing");
-
-	e = pool->free_list;
-	if (e)
-		pool->free_list = e->next;
-
-	return e;
-}
-
-/**
- * \brief Get a buffer from the memory pool.
- * This version is locked and should be used when multiple threads access the
- * same memory pool.
- * \param[in] pool memory pool
- * \return Returns a pointer to the buffer or NULL if none is available.
- */
-void *uffs_PoolGetLocked(uffs_Pool *pool)
-{
-	uffs_PoolEntry *e;
-
-	uffs_Assert(pool, "pool missing");
-
-	uffs_SemWait(pool->sem);
-	e = pool->free_list;
-	if (e)
-		pool->free_list = e->next;
-	uffs_SemSignal(pool->sem);
-
-	return e;
-}
-
-/**
- * \brief Puts a buffer back to the memory pool.
- * \param[in] pool memory pool
- * \param[in] p buffer to put back
- * \return Returns 0 if successful.
- */
-int uffs_PoolPut(uffs_Pool *pool, void *p)
-{
-	uffs_PoolEntry *e = (uffs_PoolEntry *)p;
-
-	uffs_Assert(pool, "pool missing");
-
-	if (e) {
-		e->next = pool->free_list;
-		pool->free_list = e;
-		return 0;
-	}
-
-	return -1;
-}
-
-/**
- * \brief Puts a buffer back to the memory pool.
- * This version is locked and should be used when multiple threads access the
- * same memory pool.
- * \param[in] pool memory pool
- * \param[in] p buffer to put back
- * \return Returns 0 if successful.
- */
-int uffs_PoolPutLocked(uffs_Pool *pool, void *p)
-{
-	uffs_PoolEntry *e = (uffs_PoolEntry *)p;
-
-	uffs_Assert(pool, "pool missing");
-
-	if (e) {
-		uffs_SemWait(pool->sem);
-		e->next = pool->free_list;
-		pool->free_list = e;
-		uffs_SemSignal(pool->sem);
-		return 0;
-	}
-
-	return -1;
-}
-
-/**
- * \brief Gets a buffer by index (offset).
- * This method returns a buffer from the memory pool by index.
- * \param[in] pool memory pool
- * \param[in] index index
- * \return Returns a pointer to the buffer.
- */
-void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index)
-{
-	uffs_Assert(pool, "pool missing");
-	uffs_Assert(index >= 0 && index < pool->num_bufs, "index out of range");
-
-	return (u8 *) pool->mem + index * pool->buf_size;
-}
-
-/**
- * \brief Gets the index (offset) of a buffer.
- * This method returns the index of a buffer from the memory pool.
- * \param[in] pool memory pool
- * \param[in] p buffer to get index from
- * \return Returns the index of the buffer.
- */
-u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p)
-{
-	uffs_Assert(pool, "pool missing");
-	uffs_Assert(p >= (void *) pool->mem &&
-			p < (void *) (pool->mem + pool->num_bufs * pool->buf_size),
-			"pointer out of range");
-
-	return ((u8 *) p - pool->mem) / pool->buf_size;
-}
-
-/**
- * \brief Check given buffer in free list
- * \return U_TRUE if it's in free list, U_FALSE if not.
- */
-UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p)
-{
-	uffs_PoolEntry *e;
-	for (e = pool->free_list; e; e = e->next) {
-		if ((void *)e == p)
-			return U_TRUE;
-	}
-	return U_FALSE;
-}
-
-/**
- * \brief this is more efficient version for small nodes number memory pool (< 32)
- */
-static void * FindNextAllocatedInSmallPool(uffs_Pool *pool, void *from)
-{
-	u32 map = 0;
-	uffs_PoolEntry *e;
-	u32 i;
-
-	for (e = pool->free_list; e; e = e->next)
-		map |= (1 << uffs_PoolGetIndex(pool, e));
-
-	for (i = uffs_PoolGetIndex(pool, from); (map & (1 << i)) && i < 32; i++);
-
-	return i < 32 ? uffs_PoolGetBufByIndex(pool, i) : NULL;
-}
-
-
-/**
- * \brief Find next allocated memory block
- *
- * \param[in] pool memory pool
- * \param[in] from search start address, if NULL, from pool->mem
- *
- * \return next allocated memory block, NULL if not found.
- *
- * \note This is NOT efficient, don't do it on a pool with large free nodes !
- */
-void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from)
-{
-	uffs_PoolEntry *e = NULL;
-	u8 *p = (u8 *)from;
-
-	if (p == NULL)
-		p = pool->mem;
-	else
-		p += pool->buf_size;
-
-	if (pool->num_bufs < 32)
-		return FindNextAllocatedInSmallPool(pool, p);
-
-	// work through the free list, stop if not in free list,
-	// otherwise move to next entry and search free list again.
-
-	if (pool->free_list) {
-		while (e == NULL && uffs_PoolVerify(pool, p)) {
-			e = pool->free_list;
-			while (e) {
-				if (p == (u8 *)e) {
-					p += pool->buf_size; // in free list, move to next entry
-					break;
-				}
-				e = e->next;
-			}
-		}
-	}
-
-	return uffs_PoolVerify(pool, p) ? p : NULL ;
-}
-
-/**
- * \brief get free memory block count
- */
-int uffs_PoolGetFreeCount(uffs_Pool *pool)
-{
-	int count = 0;
-	uffs_PoolEntry *e;
-
-	e = pool->free_list;
-	while (e) {
-		count++;
-		e = e->next;
-	}
-
-	return count;
-}
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/** 
+ * \file uffs_pool.c
+ * \brief Fast fixed size memory pool management.
+ * \author Ricky Zheng, Simon Kallweit
+ */
+ 
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_pool.h"
+
+/*
+
+	usage:
+
+	#define BUF_SIZE	32
+	#define NUM_BUFS	1024
+
+	static int pool_mem[NUM_BUFS * BUF_SIZE / sizeof(int)];
+	static uffs_Pool pool;
+
+	uffs_PoolInit(&pool, pool_mem, sizeof(pool_mem), BUF_SIZE, NUM_BUFS);
+
+	void * p;
+	p = uffs_PoolGet(&pool);
+	...
+	uffs_PoolPut(p, &pool);
+
+	notice:
+
+	uffs_PoolInit will assert when NUM_BUFS is not at least 1, or BUF_SIZE is
+	not	aligned to the platforms pointer size.
+
+*/
+
+
+/**
+ * \brief Initializes the memory pool.
+ * \param[in] pool memory pool
+ * \param[in] mem pool memory
+ * \param[in] mem_size size of pool memory
+ * \param[in] buf_size size of a single buffer
+ * \param[in] num_bufs number of buffers
+ * \return Returns U_SUCC if successful.
+ */
+URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs)
+{
+	unsigned int i;
+	uffs_PoolEntry *e1, *e2;
+
+	uffs_Assert(pool, "pool missing");
+	uffs_Assert(mem, "pool memory missing");
+	uffs_Assert(num_bufs > 0, "not enough buffers");
+	uffs_Assert(buf_size % sizeof(void *) == 0, "buffer size not aligned to pointer size");
+	uffs_Assert(mem_size == num_bufs * buf_size, "pool memory size is wrong");
+
+	pool->mem = (u8 *)mem;
+	pool->buf_size = buf_size;
+	pool->num_bufs = num_bufs;
+	pool->sem = uffs_SemCreate(1);
+	
+	uffs_SemWait(pool->sem);
+
+	// Initialize the free_list
+	e1 = e2 = pool->free_list = (uffs_PoolEntry *) pool->mem;
+	for (i = 1; i < pool->num_bufs; i++) {
+		e2 = (uffs_PoolEntry *) (pool->mem + i * pool->buf_size);
+		e1->next = e2;
+		e1 = e2;
+	}
+	e2->next = NULL;
+	
+	uffs_SemSignal(pool->sem);
+
+	return U_SUCC;
+}
+
+/**
+ * \brief verify pointer validity aganist memory pool
+ * \return U_TRUE if valid, U_FALSE if invalid.
+ */
+UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p)
+{
+	return  p &&
+			(u8 *)p >= pool->mem &&
+			(u8 *)p < pool->mem + (pool->buf_size * pool->num_bufs) &&
+			(((u8 *)p - pool->mem) % pool->buf_size) == 0	? U_TRUE : U_FALSE;
+}
+
+/**
+ * \brief Releases the memory pool.
+ * \param[in] pool memory pool
+ * \return Returns U_SUCC if successful.
+ */
+URET uffs_PoolRelease(uffs_Pool *pool)
+{
+	uffs_Assert(pool, "pool missing");
+	
+	uffs_SemDelete(pool->sem);
+	pool->sem = 0;
+
+	return U_SUCC;
+}
+
+/**
+ * \brief Get a buffer from the memory pool.
+ * \param[in] pool memory pool
+ * \return Returns a pointer to the buffer or NULL if none is available.
+ */
+void *uffs_PoolGet(uffs_Pool *pool)
+{
+	uffs_PoolEntry *e;
+
+	uffs_Assert(pool, "pool missing");
+
+	e = pool->free_list;
+	if (e)
+		pool->free_list = e->next;
+
+	return e;
+}
+
+/**
+ * \brief Get a buffer from the memory pool.
+ * This version is locked and should be used when multiple threads access the
+ * same memory pool.
+ * \param[in] pool memory pool
+ * \return Returns a pointer to the buffer or NULL if none is available.
+ */
+void *uffs_PoolGetLocked(uffs_Pool *pool)
+{
+	uffs_PoolEntry *e;
+
+	uffs_Assert(pool, "pool missing");
+
+	uffs_SemWait(pool->sem);
+	e = pool->free_list;
+	if (e)
+		pool->free_list = e->next;
+	uffs_SemSignal(pool->sem);
+
+	return e;
+}
+
+/**
+ * \brief Puts a buffer back to the memory pool.
+ * \param[in] pool memory pool
+ * \param[in] p buffer to put back
+ * \return Returns 0 if successful.
+ */
+int uffs_PoolPut(uffs_Pool *pool, void *p)
+{
+	uffs_PoolEntry *e = (uffs_PoolEntry *)p;
+
+	uffs_Assert(pool, "pool missing");
+
+	if (e) {
+		e->next = pool->free_list;
+		pool->free_list = e;
+		return 0;
+	}
+
+	return -1;
+}
+
+/**
+ * \brief Puts a buffer back to the memory pool.
+ * This version is locked and should be used when multiple threads access the
+ * same memory pool.
+ * \param[in] pool memory pool
+ * \param[in] p buffer to put back
+ * \return Returns 0 if successful.
+ */
+int uffs_PoolPutLocked(uffs_Pool *pool, void *p)
+{
+	uffs_PoolEntry *e = (uffs_PoolEntry *)p;
+
+	uffs_Assert(pool, "pool missing");
+
+	if (e) {
+		uffs_SemWait(pool->sem);
+		e->next = pool->free_list;
+		pool->free_list = e;
+		uffs_SemSignal(pool->sem);
+		return 0;
+	}
+
+	return -1;
+}
+
+/**
+ * \brief Gets a buffer by index (offset).
+ * This method returns a buffer from the memory pool by index.
+ * \param[in] pool memory pool
+ * \param[in] index index
+ * \return Returns a pointer to the buffer.
+ */
+void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index)
+{
+	uffs_Assert(pool, "pool missing");
+	uffs_Assert(index < pool->num_bufs, "index out of range");
+
+	return (u8 *) pool->mem + index * pool->buf_size;
+}
+
+/**
+ * \brief Gets the index (offset) of a buffer.
+ * This method returns the index of a buffer from the memory pool.
+ * \param[in] pool memory pool
+ * \param[in] p buffer to get index from
+ * \return Returns the index of the buffer.
+ */
+u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p)
+{
+	uffs_Assert(pool, "pool missing");
+	uffs_Assert(p >= (void *) pool->mem &&
+			p < (void *) (pool->mem + pool->num_bufs * pool->buf_size),
+			"pointer out of range");
+
+	return ((u8 *) p - pool->mem) / pool->buf_size;
+}
+
+/**
+ * \brief Check given buffer in free list
+ * \return U_TRUE if it's in free list, U_FALSE if not.
+ */
+UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p)
+{
+	uffs_PoolEntry *e;
+	for (e = pool->free_list; e; e = e->next) {
+		if ((void *)e == p)
+			return U_TRUE;
+	}
+	return U_FALSE;
+}
+
+/**
+ * \brief this is more efficient version for small nodes number memory pool (< 32)
+ */
+static void * FindNextAllocatedInSmallPool(uffs_Pool *pool, void *from)
+{
+	u32 map = 0;
+	uffs_PoolEntry *e;
+	u32 i;
+
+	for (e = pool->free_list; e; e = e->next)
+		map |= (1 << uffs_PoolGetIndex(pool, e));
+
+	for (i = uffs_PoolGetIndex(pool, from); (map & (1 << i)) && i < 32; i++);
+
+	return i < 32 ? uffs_PoolGetBufByIndex(pool, i) : NULL;
+}
+
+
+/**
+ * \brief Find next allocated memory block
+ *
+ * \param[in] pool memory pool
+ * \param[in] from search start address, if NULL, from pool->mem
+ *
+ * \return next allocated memory block, NULL if not found.
+ *
+ * \note This is NOT efficient, don't do it on a pool with large free nodes !
+ */
+void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from)
+{
+	uffs_PoolEntry *e = NULL;
+	u8 *p = (u8 *)from;
+
+	if (p == NULL)
+		p = pool->mem;
+	else
+		p += pool->buf_size;
+
+	if (pool->num_bufs < 32)
+		return FindNextAllocatedInSmallPool(pool, p);
+
+	// work through the free list, stop if not in free list,
+	// otherwise move to next entry and search free list again.
+
+	if (pool->free_list) {
+		while (e == NULL && uffs_PoolVerify(pool, p)) {
+			e = pool->free_list;
+			while (e) {
+				if (p == (u8 *)e) {
+					p += pool->buf_size; // in free list, move to next entry
+					break;
+				}
+				e = e->next;
+			}
+		}
+	}
+
+	return uffs_PoolVerify(pool, p) ? p : NULL ;
+}
+
+/**
+ * \brief get free memory block count
+ */
+int uffs_PoolGetFreeCount(uffs_Pool *pool)
+{
+	int count = 0;
+	uffs_PoolEntry *e;
+
+	e = pool->free_list;
+	while (e) {
+		count++;
+		e = e->next;
+	}
+
+	return count;
+}

+ 533 - 533
components/dfs/filesystems/uffs/src/uffs/uffs_public.c

@@ -1,533 +1,533 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_public.c
- * \brief public and miscellaneous functions
- * \author Ricky Zheng, created 10th May, 2005
- */
-
-#include "uffs/uffs_types.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_core.h"
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_os.h"
-
-#include <string.h>
-
-#define PFX "pub: "
-
-
-int uffs_GetFirstBlockTimeStamp(void)
-{
-	return 0;
-}
-
-int uffs_GetNextBlockTimeStamp(int prev)
-{
-	return (prev + 1) % 3;
-}
-
-UBOOL uffs_IsSrcNewerThanObj(int src, int obj)
-{
-	switch (src - obj) {
-	case 0:
-		uffs_Perror(UFFS_ERR_SERIOUS,  "the two block have the same time stamp ?");
-		break;
-	case 1:
-	case -2:
-		return U_TRUE;
-	case -1:
-	case 2:
-		return U_FALSE;
-	default:
-		uffs_Perror(UFFS_ERR_SERIOUS,  "time stamp out of range !");
-		break;
-	}
-
-	return U_FALSE;
-}
-
-
-/** 
- * \brief given a page, search the block to find a better page with the same page id
- *
- * \param[in] dev uffs device
- * \param[in] bc block info
- * \param[in] page page number to be compared with
- *
- * \return the better page number, could be the same with the given page
- */
-u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
-{
-	int i;
-	int best;
-	uffs_Tags *tag, *tag_old;
-
-	if (page == dev->attr->pages_per_block - 1)
-		return page;
-	
-	uffs_BlockInfoLoad(dev, bc, page); //load old page
-	tag_old = GET_TAG(bc, page);
-
-	for (i = dev->attr->pages_per_block - 1; i > page; i--) {
-		uffs_BlockInfoLoad(dev, bc, i);
-		tag = GET_TAG(bc, i);
-		if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
-			if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
-				TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
-				TAG_IS_DIRTY(tag) &&		//0: dirty, 1:clear
-				TAG_IS_VALID(tag_old)) {	//0: valid, 1:invalid
-					break;
-			}
-		}
-	}
-	best = i;
-
-#if 0
-	if (TAG_PAGE_ID(tag_old) == page) {
-		//well, try to speed up by probing the last page ....
-		uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
-		tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
-		if (TAG_IS_VALID(tag) &&
-			TAG_IS_DIRTY(tag) &&
-			TAG_PAGE_ID(tag) == dev->attr->pages_per_block - 1) {
-			return page;
-		}
-	}
-
-	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
-	best = page;
-	//the better page must be ahead of page, so ...i = page + 1; i < ...
-	for (i = page + 1; i < dev->attr->pages_per_block; i++) {
-		tag = GET_TAG(bc, i);
-		if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
-			if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
-				TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
-				TAG_IS_DIRTY(tag) &&		//0: dirty, 1:clear
-				TAG_IS_VALID(tag_old)) {	//0: valid, 1:invalid
-				if (i > best) 
-					best = i;
-			}
-		}
-	}
-#endif
-
-	return best;
-}
-
-/** 
- * \brief find a valid page with given page_id
- * \param[in] dev uffs device
- * \param[in] bc block info
- * \param[in] page_id page_id to be find
- * \return the valid page number which has given page_id
- * \retval >=0 page number
- * \retval UFFS_INVALID_PAGE page not found
- */
-u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id)
-{
-	u16 page;
-	uffs_Tags *tag;
-
-	//Indeed, the page which has page_id, should ahead of page_id ...
-	for (page = page_id; page < dev->attr->pages_per_block; page++) {
-		uffs_BlockInfoLoad(dev, bc, page);
-		tag = &(bc->spares[page].tag);
-		if (TAG_PAGE_ID(tag) == page_id)
-			return page;
-	}
-
-	return UFFS_INVALID_PAGE;
-}
-
-/** 
- * Are all the pages in the block used ?
- */
-UBOOL uffs_IsBlockPagesFullUsed(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	uffs_Tags *tag;
-
-	// if the last page is dirty, then the whole block is full
-	uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
-	tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
-
-	return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
-}
-
-/** 
- * Is this block used ?
- * \param[in] dev uffs device
- * \param[in] bc block info
- * \retval U_TRUE block is used
- * \retval U_FALSE block is free
- */
-UBOOL uffs_IsThisBlockUsed(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	uffs_Tags *tag;
-
-	// if the first page is dirty, then this block is used.
-	uffs_BlockInfoLoad(dev, bc, 0);
-	tag = GET_TAG(bc, 0);
-
-	return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
-}
-
-/** 
- * get block time stamp from a exist block
- * \param[in] dev uffs device
- * \param[in] bc block info
- */
-int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	if(uffs_IsThisBlockUsed(dev, bc) == U_FALSE) 
-		return uffs_GetFirstBlockTimeStamp();
-	else{
-		uffs_BlockInfoLoad(dev, bc, 0);
-		return TAG_BLOCK_TS(GET_TAG(bc, 0));
-	}
-
-}
-
-/** 
- * find first free page from 'pageFrom'
- * \param[in] dev uffs device
- * \param[in] bc block info
- * \param[in] pageFrom search from this page
- * \return return first free page number from 'pageFrom'
- * \retval UFFS_INVALID_PAGE no free page found
- * \retval >=0 the first free page number
- */
-u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom)
-{
-	u16 i;
-
-	for (i = pageFrom; i < dev->attr->pages_per_block; i++) {
-		uffs_BlockInfoLoad(dev, bc, i);
-		if (uffs_IsPageErased(dev, bc, i) == U_TRUE)
-			return i;
-	}
-
-	return UFFS_INVALID_PAGE; //free page not found
-}
-
-
-/** 
- * Find first valid page from a block, just used in mounting a partition
- */
-u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	u16 i;
-
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		if (uffs_BlockInfoLoad(dev, bc, i) == U_SUCC)
-			return i;
-	}
-	return UFFS_INVALID_PAGE;
-}
-
-
-/** 
- * calculate sum of data, 8bit version
- * \param[in] p data pointer
- * \param[in] len length of data
- * \return return sum of data, 8bit
- */
-u8 uffs_MakeSum8(const void *p, int len)
-{
-	u8 ret = 0;
-	const u8 *data = (const u8 *)p;
-
-	if (!p)
-		return 0;
-
-	while (len > 0) {
-		ret += *data++;
-		len--;
-	}
-
-	return ret;
-}
-
-/** 
- * calculate sum of datam, 16bit version
- * \param[in] p data pointer
- * \param[in] len length of data
- * \return return sum of data, 16bit
- */
-u16 uffs_MakeSum16(const void *p, int len)
-{
-	u8 ret_lo = 0;
-	u8 ret_hi = 0;
-	const u8 *data = (const u8 *)p;
-
-	if (!p)
-		return 0;
-
-	while (len > 0) {
-		ret_lo += *data;
-		ret_hi ^= *data;
-		data++;
-		len--;
-	}
-
-	return (ret_hi << 8) | ret_lo;
-}
-
-/** 
- * create a new file on a free block
- * \param[in] dev uffs device
- * \param[in] parent parent dir serial num
- * \param[in] serial serial num of this new file
- * \param[in] bc block information
- * \param[in] fi file information
- * \note parent, serial, bc must be provided before, and all information in fi should be filled well before.
- */
-URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi)
-{
-	uffs_Tags *tag;
-	uffs_Buf *buf;
-
-	uffs_BlockInfoLoad(dev, bc, 0);
-
-	tag = GET_TAG(bc, 0);
-	TAG_PARENT(tag) = parent;
-	TAG_SERIAL(tag) = serial;
-	TAG_DATA_LEN(tag) = sizeof(uffs_FileInfo);
-	//tag->data_sum = uffs_MakeSum16(fi->name, fi->name_len);
-
-	buf = uffs_BufGet(dev, parent, serial, 0);
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "get buf fail.");
-		return U_FAIL;
-	}
-
-	memcpy(buf->data, fi, TAG_DATA_LEN(tag));
-	buf->data_len = TAG_DATA_LEN(tag);
-
-	return uffs_BufPut(dev, buf);
-}
-
-
-/** 
- * \brief calculate data length of a file block
- * \param[in] dev uffs device
- * \param[in] bc block info
- */
-int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type)
-{
-	u16 page_id;
-	u16 i;
-	uffs_Tags *tag;
-	int size = 0;
-	u16 page;
-	u16 lastPage = dev->attr->pages_per_block - 1;
-
-	// TODO: Need to speed up this procedure!
-	// First try the last page. will hit it if it's the full loaded file/data block.
-	uffs_BlockInfoLoad(dev, bc, lastPage);
-	tag = GET_TAG(bc, lastPage);
-
-	if (type == UFFS_TYPE_FILE) {
-		if(TAG_PAGE_ID(tag) == (lastPage - 1) &&
-			TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
-			size = dev->com.pg_data_size * (dev->attr->pages_per_block - 1);
-			return size;
-		}
-	}
-	if (type == UFFS_TYPE_DATA) {
-		if(TAG_PAGE_ID(tag) == lastPage &&
-			TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
-			size = dev->com.pg_data_size * dev->attr->pages_per_block;
-			return size;
-		}
-	}
-
-	// ok, it's not the full loaded file/data block, need to read all spares....
-	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
-	tag = GET_TAG(bc, 0);
-	if (TAG_TYPE(tag) == UFFS_TYPE_FILE) {
-		page_id = 1; //In file header block, file data page_id from 1
-		i = 1;		//search from page 1
-	}
-	else {
-		page_id = 0;	//in normal file data block, page_id from 0
-		i = 0;		//in normal file data block, search from page 0
-	}
-	for (; i < dev->attr->pages_per_block; i++) {
-		tag = GET_TAG(bc, i);
-		if (page_id == TAG_PAGE_ID(tag)) {
-			page = uffs_FindBestPageInBlock(dev, bc, i);
-			size += TAG_DATA_LEN(GET_TAG(bc, page));
-			page_id++;
-		}
-	}
-
-	return size;
-}
-
-/** 
- * get free pages number
- * \param[in] dev uffs device
- * \param[in] bc block info
- */
-int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	int count = 0;
-	int i;
-
-	for (i = dev->attr->pages_per_block - 1; i >= 0; i--) {
-		uffs_BlockInfoLoad(dev, bc, i);
-		if (uffs_IsPageErased(dev, bc, (u16)i) == U_TRUE) {
-			count++;
-		}
-		else break;
-	}
-
-	return count;
-}
-/** 
- * \brief Is the block erased ?
- * \param[in] dev uffs device
- * \param[in] bc block info
- * \param[in] page page number to be check
- * \retval U_TRUE block is erased, ready to use
- * \retval U_FALSE block is dirty, maybe use by file
- */
-UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
-{
-	uffs_Tags *tag;
-
-	uffs_BlockInfoLoad(dev, bc, page);
-	tag = GET_TAG(bc, page);
-
-	if (!TAG_IS_DIRTY(tag) &&
-		!TAG_IS_VALID(tag)) {
-		return U_TRUE;
-	}
-
-	return U_FALSE;
-}
-
-/** 
- * \brief Is this block the last block of file ? (no free pages, and full filled with full page_id)
- */
-UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	uffs_Tags *tag;
-	uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
-
-	tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
-
-	if (TAG_PAGE_ID(tag) == (dev->attr->pages_per_block - 1) &&
-		TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
-		return U_TRUE;
-	}
-	return U_FALSE;
-}
-
-/** 
- * get partition used (bytes)
- */
-int uffs_GetDeviceUsed(uffs_Device *dev)
-{
-	return (dev->par.end - dev->par.start + 1 - dev->tree.bad_count
-				- dev->tree.erased_count) * dev->attr->page_data_size * dev->attr->pages_per_block;
-}
-
-/** 
- * get partition free (bytes)
- */
-int uffs_GetDeviceFree(uffs_Device *dev)
-{
-	return dev->tree.erased_count * dev->attr->page_data_size * dev->attr->pages_per_block;
-}
-
-/** 
- * get partition total size (bytes)
- */
-int uffs_GetDeviceTotal(uffs_Device *dev)
-{
-	return (dev->par.end - dev->par.start + 1) * dev->attr->page_data_size * dev->attr->pages_per_block;
-}
-
-/**
- * load mini hader from flash
- */
-URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header)
-{
-	int ret = dev->ops->ReadPageData(dev, block, page, (u8 *)header, sizeof(struct uffs_MiniHeaderSt), NULL);
-
-	dev->st.page_header_read_count++;
-
-	return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
-}
-
-#if 0
-/** \brief transfer the standard uffs_Tags to uffs_Tags_8
- *  \param[in] tag standard uffs_Tags
- *  \param[out] tag_8 small tag to fit into 8 bytes spare space
- */
-void uffs_TransferToTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
-{
-	tag_8->dirty = tag->dirty;
-	tag_8->valid = tag->valid;
-	tag_8->type = tag->type;
-	tag_8->block_ts = tag->block_ts;
-	tag_8->page_id = tag->page_id;
-	tag_8->parent = tag->parent & 0xFF;
-	tag_8->serial = tag->serial & 0xFF;
-	tag_8->data_len = tag->data_len & 0xFF;
-	tag_8->data_sum = tag->data_sum;
-	tag_8->block_status = tag->block_status;
-}
-
-/** \brief transfer the small uffs_Tags_8 to standard uffs_Tags
- *  \param[out] tag standard uffs_Tags
- *  \param[in] tag_8 small tag to fit into 8 bytes spare space
- */
-void uffs_TransferFromTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
-{
-	tag->dirty = tag_8->dirty;
-	tag->valid = tag_8->valid;
-	tag->type = tag_8->type;
-	tag->block_ts = tag_8->block_ts;
-	tag->page_id = tag_8->page_id;
-	tag->parent = tag_8->parent;
-	tag->serial = tag_8->serial;
-	tag->data_len = tag_8->data_len;
-	tag->data_sum = tag_8->data_sum;
-	tag->block_status = tag_8->block_status;
-}
-#endif
-
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_public.c
+ * \brief public and miscellaneous functions
+ * \author Ricky Zheng, created 10th May, 2005
+ */
+
+#include "uffs/uffs_types.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_os.h"
+
+#include <string.h>
+
+#define PFX "pub: "
+
+
+int uffs_GetFirstBlockTimeStamp(void)
+{
+	return 0;
+}
+
+int uffs_GetNextBlockTimeStamp(int prev)
+{
+	return (prev + 1) % 3;
+}
+
+UBOOL uffs_IsSrcNewerThanObj(int src, int obj)
+{
+	switch (src - obj) {
+	case 0:
+		uffs_Perror(UFFS_ERR_SERIOUS,  "the two block have the same time stamp ?");
+		break;
+	case 1:
+	case -2:
+		return U_TRUE;
+	case -1:
+	case 2:
+		return U_FALSE;
+	default:
+		uffs_Perror(UFFS_ERR_SERIOUS,  "time stamp out of range !");
+		break;
+	}
+
+	return U_FALSE;
+}
+
+
+/** 
+ * \brief given a page, search the block to find a better page with the same page id
+ *
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ * \param[in] page page number to be compared with
+ *
+ * \return the better page number, could be the same with the given page
+ */
+u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
+{
+	int i;
+	int best;
+	uffs_Tags *tag, *tag_old;
+
+	if (page == dev->attr->pages_per_block - 1)
+		return page;
+	
+	uffs_BlockInfoLoad(dev, bc, page); //load old page
+	tag_old = GET_TAG(bc, page);
+
+	for (i = dev->attr->pages_per_block - 1; i > page; i--) {
+		uffs_BlockInfoLoad(dev, bc, i);
+		tag = GET_TAG(bc, i);
+		if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
+			if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
+				TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
+				TAG_IS_DIRTY(tag) &&		//0: dirty, 1:clear
+				TAG_IS_VALID(tag_old)) {	//0: valid, 1:invalid
+					break;
+			}
+		}
+	}
+	best = i;
+
+#if 0
+	if (TAG_PAGE_ID(tag_old) == page) {
+		//well, try to speed up by probing the last page ....
+		uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
+		tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
+		if (TAG_IS_VALID(tag) &&
+			TAG_IS_DIRTY(tag) &&
+			TAG_PAGE_ID(tag) == dev->attr->pages_per_block - 1) {
+			return page;
+		}
+	}
+
+	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
+	best = page;
+	//the better page must be ahead of page, so ...i = page + 1; i < ...
+	for (i = page + 1; i < dev->attr->pages_per_block; i++) {
+		tag = GET_TAG(bc, i);
+		if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
+			if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
+				TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
+				TAG_IS_DIRTY(tag) &&		//0: dirty, 1:clear
+				TAG_IS_VALID(tag_old)) {	//0: valid, 1:invalid
+				if (i > best) 
+					best = i;
+			}
+		}
+	}
+#endif
+
+	return best;
+}
+
+/** 
+ * \brief find a valid page with given page_id
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ * \param[in] page_id page_id to be find
+ * \return the valid page number which has given page_id
+ * \retval >=0 page number
+ * \retval UFFS_INVALID_PAGE page not found
+ */
+u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id)
+{
+	u16 page;
+	uffs_Tags *tag;
+
+	//Indeed, the page which has page_id, should ahead of page_id ...
+	for (page = page_id; page < dev->attr->pages_per_block; page++) {
+		uffs_BlockInfoLoad(dev, bc, page);
+		tag = &(bc->spares[page].tag);
+		if (TAG_PAGE_ID(tag) == page_id)
+			return page;
+	}
+
+	return UFFS_INVALID_PAGE;
+}
+
+/** 
+ * Are all the pages in the block used ?
+ */
+UBOOL uffs_IsBlockPagesFullUsed(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	uffs_Tags *tag;
+
+	// if the last page is dirty, then the whole block is full
+	uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
+	tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
+
+	return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
+}
+
+/** 
+ * Is this block used ?
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ * \retval U_TRUE block is used
+ * \retval U_FALSE block is free
+ */
+UBOOL uffs_IsThisBlockUsed(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	uffs_Tags *tag;
+
+	// if the first page is dirty, then this block is used.
+	uffs_BlockInfoLoad(dev, bc, 0);
+	tag = GET_TAG(bc, 0);
+
+	return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
+}
+
+/** 
+ * get block time stamp from a exist block
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ */
+int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	if(uffs_IsThisBlockUsed(dev, bc) == U_FALSE) 
+		return uffs_GetFirstBlockTimeStamp();
+	else{
+		uffs_BlockInfoLoad(dev, bc, 0);
+		return TAG_BLOCK_TS(GET_TAG(bc, 0));
+	}
+
+}
+
+/** 
+ * find first free page from 'pageFrom'
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ * \param[in] pageFrom search from this page
+ * \return return first free page number from 'pageFrom'
+ * \retval UFFS_INVALID_PAGE no free page found
+ * \retval >=0 the first free page number
+ */
+u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom)
+{
+	u16 i;
+
+	for (i = pageFrom; i < dev->attr->pages_per_block; i++) {
+		uffs_BlockInfoLoad(dev, bc, i);
+		if (uffs_IsPageErased(dev, bc, i) == U_TRUE)
+			return i;
+	}
+
+	return UFFS_INVALID_PAGE; //free page not found
+}
+
+
+/** 
+ * Find first valid page from a block, just used in mounting a partition
+ */
+u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	u16 i;
+
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		if (uffs_BlockInfoLoad(dev, bc, i) == U_SUCC)
+			return i;
+	}
+	return UFFS_INVALID_PAGE;
+}
+
+
+/** 
+ * calculate sum of data, 8bit version
+ * \param[in] p data pointer
+ * \param[in] len length of data
+ * \return return sum of data, 8bit
+ */
+u8 uffs_MakeSum8(const void *p, int len)
+{
+	u8 ret = 0;
+	const u8 *data = (const u8 *)p;
+
+	if (!p)
+		return 0;
+
+	while (len > 0) {
+		ret += *data++;
+		len--;
+	}
+
+	return ret;
+}
+
+/** 
+ * calculate sum of datam, 16bit version
+ * \param[in] p data pointer
+ * \param[in] len length of data
+ * \return return sum of data, 16bit
+ */
+u16 uffs_MakeSum16(const void *p, int len)
+{
+	u8 ret_lo = 0;
+	u8 ret_hi = 0;
+	const u8 *data = (const u8 *)p;
+
+	if (!p)
+		return 0;
+
+	while (len > 0) {
+		ret_lo += *data;
+		ret_hi ^= *data;
+		data++;
+		len--;
+	}
+
+	return (ret_hi << 8) | ret_lo;
+}
+
+/** 
+ * create a new file on a free block
+ * \param[in] dev uffs device
+ * \param[in] parent parent dir serial num
+ * \param[in] serial serial num of this new file
+ * \param[in] bc block information
+ * \param[in] fi file information
+ * \note parent, serial, bc must be provided before, and all information in fi should be filled well before.
+ */
+URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi)
+{
+	uffs_Tags *tag;
+	uffs_Buf *buf;
+
+	uffs_BlockInfoLoad(dev, bc, 0);
+
+	tag = GET_TAG(bc, 0);
+	TAG_PARENT(tag) = parent;
+	TAG_SERIAL(tag) = serial;
+	TAG_DATA_LEN(tag) = sizeof(uffs_FileInfo);
+	//tag->data_sum = uffs_MakeSum16(fi->name, fi->name_len);
+
+	buf = uffs_BufGet(dev, parent, serial, 0);
+	if (buf == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "get buf fail.");
+		return U_FAIL;
+	}
+
+	memcpy(buf->data, fi, TAG_DATA_LEN(tag));
+	buf->data_len = TAG_DATA_LEN(tag);
+
+	return uffs_BufPut(dev, buf);
+}
+
+
+/** 
+ * \brief calculate data length of a file block
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ */
+int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type)
+{
+	u16 page_id;
+	u16 i;
+	uffs_Tags *tag;
+	int size = 0;
+	u16 page;
+	u16 lastPage = dev->attr->pages_per_block - 1;
+
+	// TODO: Need to speed up this procedure!
+	// First try the last page. will hit it if it's the full loaded file/data block.
+	uffs_BlockInfoLoad(dev, bc, lastPage);
+	tag = GET_TAG(bc, lastPage);
+
+	if (type == UFFS_TYPE_FILE) {
+		if(TAG_PAGE_ID(tag) == (lastPage - 1) &&
+			TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
+			size = dev->com.pg_data_size * (dev->attr->pages_per_block - 1);
+			return size;
+		}
+	}
+	if (type == UFFS_TYPE_DATA) {
+		if(TAG_PAGE_ID(tag) == lastPage &&
+			TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
+			size = dev->com.pg_data_size * dev->attr->pages_per_block;
+			return size;
+		}
+	}
+
+	// ok, it's not the full loaded file/data block, need to read all spares....
+	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
+	tag = GET_TAG(bc, 0);
+	if (TAG_TYPE(tag) == UFFS_TYPE_FILE) {
+		page_id = 1; //In file header block, file data page_id from 1
+		i = 1;		//search from page 1
+	}
+	else {
+		page_id = 0;	//in normal file data block, page_id from 0
+		i = 0;		//in normal file data block, search from page 0
+	}
+	for (; i < dev->attr->pages_per_block; i++) {
+		tag = GET_TAG(bc, i);
+		if (page_id == TAG_PAGE_ID(tag)) {
+			page = uffs_FindBestPageInBlock(dev, bc, i);
+			size += TAG_DATA_LEN(GET_TAG(bc, page));
+			page_id++;
+		}
+	}
+
+	return size;
+}
+
+/** 
+ * get free pages number
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ */
+int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	int count = 0;
+	int i;
+
+	for (i = dev->attr->pages_per_block - 1; i >= 0; i--) {
+		uffs_BlockInfoLoad(dev, bc, i);
+		if (uffs_IsPageErased(dev, bc, (u16)i) == U_TRUE) {
+			count++;
+		}
+		else break;
+	}
+
+	return count;
+}
+/** 
+ * \brief Is the block erased ?
+ * \param[in] dev uffs device
+ * \param[in] bc block info
+ * \param[in] page page number to be check
+ * \retval U_TRUE block is erased, ready to use
+ * \retval U_FALSE block is dirty, maybe use by file
+ */
+UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
+{
+	uffs_Tags *tag;
+
+	uffs_BlockInfoLoad(dev, bc, page);
+	tag = GET_TAG(bc, page);
+
+	if (!TAG_IS_DIRTY(tag) &&
+		!TAG_IS_VALID(tag)) {
+		return U_TRUE;
+	}
+
+	return U_FALSE;
+}
+
+/** 
+ * \brief Is this block the last block of file ? (no free pages, and full filled with full page_id)
+ */
+UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	uffs_Tags *tag;
+	uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
+
+	tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
+
+	if (TAG_PAGE_ID(tag) == (dev->attr->pages_per_block - 1) &&
+		TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
+		return U_TRUE;
+	}
+	return U_FALSE;
+}
+
+/** 
+ * get partition used (bytes)
+ */
+int uffs_GetDeviceUsed(uffs_Device *dev)
+{
+	return (dev->par.end - dev->par.start + 1 - dev->tree.bad_count
+				- dev->tree.erased_count) * dev->attr->page_data_size * dev->attr->pages_per_block;
+}
+
+/** 
+ * get partition free (bytes)
+ */
+int uffs_GetDeviceFree(uffs_Device *dev)
+{
+	return dev->tree.erased_count * dev->attr->page_data_size * dev->attr->pages_per_block;
+}
+
+/** 
+ * get partition total size (bytes)
+ */
+int uffs_GetDeviceTotal(uffs_Device *dev)
+{
+	return (dev->par.end - dev->par.start + 1) * dev->attr->page_data_size * dev->attr->pages_per_block;
+}
+
+/**
+ * load mini hader from flash
+ */
+URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header)
+{
+	int ret = dev->ops->ReadPageData(dev, block, page, (u8 *)header, sizeof(struct uffs_MiniHeaderSt), NULL);
+
+	dev->st.page_header_read_count++;
+
+	return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
+}
+
+#if 0
+/** \brief transfer the standard uffs_Tags to uffs_Tags_8
+ *  \param[in] tag standard uffs_Tags
+ *  \param[out] tag_8 small tag to fit into 8 bytes spare space
+ */
+void uffs_TransferToTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
+{
+	tag_8->dirty = tag->dirty;
+	tag_8->valid = tag->valid;
+	tag_8->type = tag->type;
+	tag_8->block_ts = tag->block_ts;
+	tag_8->page_id = tag->page_id;
+	tag_8->parent = tag->parent & 0xFF;
+	tag_8->serial = tag->serial & 0xFF;
+	tag_8->data_len = tag->data_len & 0xFF;
+	tag_8->data_sum = tag->data_sum;
+	tag_8->block_status = tag->block_status;
+}
+
+/** \brief transfer the small uffs_Tags_8 to standard uffs_Tags
+ *  \param[out] tag standard uffs_Tags
+ *  \param[in] tag_8 small tag to fit into 8 bytes spare space
+ */
+void uffs_TransferFromTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
+{
+	tag->dirty = tag_8->dirty;
+	tag->valid = tag_8->valid;
+	tag->type = tag_8->type;
+	tag->block_ts = tag_8->block_ts;
+	tag->page_id = tag_8->page_id;
+	tag->parent = tag_8->parent;
+	tag->serial = tag_8->serial;
+	tag->data_len = tag_8->data_len;
+	tag->data_sum = tag_8->data_sum;
+	tag->block_status = tag_8->block_status;
+}
+#endif
+
+

+ 1171 - 1164
components/dfs/filesystems/uffs/src/uffs/uffs_tree.c

@@ -1,1164 +1,1171 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_tree.c
- * \brief seting up uffs tree data structure
- * \author Ricky Zheng, created 13th May, 2005
- */
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_pool.h"
-#include "uffs/uffs_config.h"
-#include "uffs/uffs_flash.h"
-#include "uffs/uffs_badblock.h"
-
-#include <string.h>
-
-#define TPOOL(dev) &(dev->mem.tree_pool)
-
-#define PFX "tree: "
-
-static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node);
-static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node);
-static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node);
-
-struct BlockTypeStatSt {
-	int dir;
-	int file;
-	int data;
-};
-
-/** 
- * \brief initialize tree buffers
- * \param[in] dev uffs device
- */
-URET uffs_TreeInit(uffs_Device *dev)
-{
-	int size;
-	int num;
-	uffs_Pool *pool;
-	int i;
-
-	size = sizeof(TreeNode);
-	num = dev->par.end - dev->par.start + 1;
-	
-	pool = &(dev->mem.tree_pool);
-
-	if (dev->mem.tree_nodes_pool_size == 0) {
-		if (dev->mem.malloc) {
-			dev->mem.tree_nodes_pool_buf = dev->mem.malloc(dev, size * num);
-			if (dev->mem.tree_nodes_pool_buf)
-				dev->mem.tree_nodes_pool_size = size * num;
-		}
-	}
-	if (size * num > dev->mem.tree_nodes_pool_size) {
-		uffs_Perror(UFFS_ERR_DEAD, "Tree buffer require %d but only %d available.", size * num, dev->mem.tree_nodes_pool_size);
-		memset(pool, 0, sizeof(uffs_Pool));
-		return U_FAIL;
-	}
-	uffs_Perror(UFFS_ERR_NOISY, "alloc tree nodes %d bytes.", size * num);
-	
-	uffs_PoolInit(pool, dev->mem.tree_nodes_pool_buf, dev->mem.tree_nodes_pool_size, size, num);
-
-	dev->tree.erased = NULL;
-	dev->tree.erased_tail = NULL;
-	dev->tree.erased_count = 0;
-	dev->tree.bad = NULL;
-	dev->tree.bad_count = 0;
-
-	for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) {
-		dev->tree.dir_entry[i] = EMPTY_NODE;
-	}
-
-	for (i = 0; i < FILE_NODE_ENTRY_LEN; i++) {
-		dev->tree.file_entry[i] = EMPTY_NODE;
-	}
-
-	for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) {
-		dev->tree.data_entry[i] = EMPTY_NODE;
-	}
-
-	dev->tree.max_serial = ROOT_DIR_SERIAL;
-	
-	return U_SUCC;
-}
-/** 
- * \brief release tree buffers, call this function when unmount
- * \param[in] dev uffs device
- */
-URET uffs_TreeRelease(uffs_Device *dev)
-{
-	uffs_Pool *pool;
-	
-	pool = &(dev->mem.tree_pool);
-	if (pool->mem && dev->mem.free) {
-		dev->mem.free(dev, pool->mem);
-		pool->mem = NULL;
-		dev->mem.tree_nodes_pool_size = 0;
-	}
-	uffs_PoolRelease(pool);
-	memset(pool, 0, sizeof(uffs_Pool));
-
-	return U_SUCC;
-}
-
-static u16 _GetBlockFromNode(u8 type, TreeNode *node)
-{
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		return node->u.dir.block;
-	case UFFS_TYPE_FILE:
-		return node->u.file.block;
-	case UFFS_TYPE_DATA:
-		return node->u.data.block;
-	}
-	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-block");
-	return UFFS_INVALID_BLOCK;
-}
-
-#if 0
-static u16 _GetParentFromNode(u8 type, TreeNode *node)
-{
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		return node->u.dir.parent;
-	case UFFS_TYPE_FILE:
-		return node->u.file.parent;
-	case UFFS_TYPE_DATA:
-		return node->u.data.parent;
-	}
-	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-parent");
-	return INVALID_UFFS_SERIAL;
-}
-
-
-static u16 _GetSerialFromNode(u8 type, TreeNode *node)
-{
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		return node->u.dir.serial;
-	case UFFS_TYPE_FILE:
-		return node->u.file.serial;
-	case UFFS_TYPE_DATA:
-		return node->u.data.serial;
-	}
-	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-serial");
-	return INVALID_UFFS_SERIAL;
-}
-#endif
-
-/** 
- * insert a TreeNode *node to tree
- * \param[in] dev uffs device
- * \param[in] type type of node
- * \param[in] node node to be insert to
- */
-void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node)
-{
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		uffs_InsertToDirEntry(dev, node);
-		break;
-	case UFFS_TYPE_FILE:
-		uffs_InsertToFileEntry(dev, node);
-		break;
-	case UFFS_TYPE_DATA:
-		uffs_InsertToDataEntry(dev, node);
-		break;
-	default:
-		uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, can't insert to tree");
-		break;
-	}
-}
-
-/** 
- * find a node from tree
- * \param[in] dev uffs device
- * \param[in] type type of node
- * \param[in] parent parent serial num
- * \param[in] serial serial num
- */
-TreeNode * uffs_FindFromTree(uffs_Device *dev, u8 type, u16 parent, u16 serial)
-{
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		return uffs_TreeFindDirNode(dev, serial);
-	case UFFS_TYPE_FILE:
-		return uffs_TreeFindFileNode(dev, serial);
-	case UFFS_TYPE_DATA:
-		return uffs_TreeFindDataNode(dev, parent, serial);
-	}
-	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, can't find node");
-	return NULL;
-}
-
-
-
-static URET _BuildValidTreeNode(uffs_Device *dev,
-								TreeNode *node,		//!< empty node
-								uffs_BlockInfo *bc,
-								struct BlockTypeStatSt *st)
-{
-	uffs_Tags *tag;
-	TreeNode *node_alt;
-	u16 block, parent, serial, block_alt, block_save;
-	uffs_BlockInfo *bc_alt;
-	u8 type;
-	int page;
-	UBOOL needToInsertToTree = U_FALSE;
-	uffs_Buf *buf = NULL;
-	uffs_FileInfo *info;
-	u16 data_sum = 0;
-
-	// check the first page on the block ...
-	uffs_BlockInfoLoad(dev, bc, 0);
-
-	tag = GET_TAG(bc, 0);  //get first page's tag
-
-	if (!TAG_IS_DIRTY(tag)) {
-		uffs_Perror(UFFS_ERR_NORMAL, "First page is clean in a non-erased block ?");
-		return U_FAIL;
-	}
-
-	if (!TAG_IS_VALID(tag)) {
-		//first page is invalid ? should be erased now!
-		uffs_Perror(UFFS_ERR_NORMAL, "first page in block %d is invalid, will be erased now!", bc->block);
-		goto process_invalid_block;		
-	}
-
-	block = bc->block;
-	parent = TAG_PARENT(tag);
-	serial = TAG_SERIAL(tag);
-	type = TAG_TYPE(tag);
-
-	// check if there is an 'alternative block' (node which has the same serial number) in tree ?
-	node_alt = uffs_FindFromTree(dev, type, parent, serial); 
-
-	if (node_alt != NULL) {
-		//find a alternate node ! need to check the timestamp !
-
-		block_alt = _GetBlockFromNode(type, node_alt);
-
-		uffs_Perror(UFFS_ERR_NORMAL, "Process unclean block (%d vs %d)", block, block_alt);
-
-		if (block_alt == INVALID_UFFS_SERIAL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "invalid block ?");
-			return U_FAIL;
-		}
-		
-		bc_alt = uffs_BlockInfoGet(dev, block_alt);
-		if (bc_alt == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "can't get block info ");
-			return U_FAIL;
-		}
-		uffs_BlockInfoLoad(dev, bc_alt, 0);
-		if (uffs_IsSrcNewerThanObj (
-				TAG_BLOCK_TS(tag),
-				TAG_BLOCK_TS(GET_TAG(bc_alt, 0))) == U_TRUE) {
-
-			//the node is newer than node_alt, so keep node_alt, and erase node
-			uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-			uffs_FlashEraseBlock(dev, block);
-			node->u.list.block = block;
-			if (HAVE_BADBLOCK(dev))
-				uffs_BadBlockProcess(dev, node);
-			else
-				uffs_TreeInsertToErasedListTail(dev, node);
-
-			uffs_BlockInfoPut(dev, bc_alt);  //put back bc_alt before we return.
-			return U_SUCC;
-		}
-		else {
-			//the node is older than node_alt, so keep node, and erase node_alt
-			//we use node as erased node to insert to erased list
-
-			block_save = _GetBlockFromNode(type, node_alt);
-			uffs_FlashEraseBlock(dev, block_save);
-			uffs_BlockInfoExpire(dev, bc_alt, UFFS_ALL_PAGES);
-			node->u.list.block = block_save;
-			if (HAVE_BADBLOCK(dev))
-				uffs_BadBlockProcess(dev, node);
-			else
-				uffs_TreeInsertToErasedListTail(dev, node);
-
-			uffs_BlockInfoPut(dev, bc_alt);  //put back bc_alt because we don't need it anymore.
-			
-			node = node_alt;	//use node_alt to store new informations in following
-			needToInsertToTree = U_FALSE;
-		}
-	}
-	else {
-		needToInsertToTree = U_TRUE;
-	}
-
-	if (type == UFFS_TYPE_DIR || type == UFFS_TYPE_FILE) {
-		buf = uffs_BufClone(dev, NULL);
-		if (buf == NULL)
-			return U_FAIL;
-		uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
-		page = uffs_FindPageInBlockWithPageId(dev, bc, 0);
-		if (page == UFFS_INVALID_PAGE) {
-			uffs_BufFreeClone(dev, buf);
-			uffs_Perror(UFFS_ERR_SERIOUS, "Can't find any valid page for page_id=0 ? invalid block !"
-												"this might be caused by the tag layout change.\n");
-			goto process_invalid_block;
-		}
-		page = uffs_FindBestPageInBlock(dev, bc, page);
-		uffs_FlashReadPage(dev, block, page, buf);
-		info = (uffs_FileInfo *) (buf->data);
-		data_sum = uffs_MakeSum16(info->name, info->name_len);
-		uffs_BufFreeClone(dev, buf);
-	}
-
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		node->u.dir.block = bc->block;
-		node->u.dir.checksum = data_sum;
-		node->u.dir.parent = TAG_PARENT(tag);
-		node->u.dir.serial = TAG_SERIAL(tag);
-		st->dir++;
-		break;
-	case UFFS_TYPE_FILE:
-		node->u.file.block = bc->block;
-		node->u.file.checksum = data_sum;
-		node->u.file.parent = TAG_PARENT(tag);
-		node->u.file.serial = TAG_SERIAL(tag);
-		node->u.file.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_FILE);  
-		st->file++;
-		break;
-	case UFFS_TYPE_DATA:
-		node->u.data.block = bc->block;
-		node->u.data.parent = TAG_PARENT(tag);
-		node->u.data.serial = TAG_SERIAL(tag);
-		node->u.data.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_DATA); 
-		st->data++;
-		break;
-	}
-
-	if (needToInsertToTree == U_TRUE) {
-		uffs_InsertNodeToTree(dev, type, node);
-	}
-
-	return U_SUCC;
-
-process_invalid_block:
-	/* erase the invalid block */
-	uffs_FlashEraseBlock(dev, bc->block);
-	uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
-
-	node->u.list.block = bc->block;
-	if (HAVE_BADBLOCK(dev))
-		uffs_BadBlockProcess(dev, node);
-	else
-		uffs_TreeInsertToErasedListTail(dev, node);
-
-	return U_SUCC;
-}
-
-
-static URET _ScanAndFixUnCleanPage(uffs_Device *dev, uffs_BlockInfo *bc)
-{
-	int page;
-	uffs_Tags *tag;
-	struct uffs_MiniHeaderSt header;
-
-	/* in most case, the valid block contents fewer free page,
-		so it's better scan from the last page ... to page 1.
-		note: scaning page 0 is not necessary.
-
-		The worse case: read (pages_per_block - 1) * (mini header + spares) !
-		most case: read one spare.
-	*/
-	for (page = dev->attr->pages_per_block - 1; page > 0; page--) {
-		uffs_BlockInfoLoad(dev, bc, page);
-		tag = GET_TAG(bc, page);
-		if (TAG_IS_DIRTY(tag) || TAG_IS_VALID(tag))  // stop if we reach a dirty or valid page
-			break;
-
-		if (uffs_LoadMiniHeader(dev, bc->block, page, &header) == U_FAIL)
-			return U_FAIL;
-
-		if (header.status != 0xFF) {
-			// ok, page data is not clean ! mark it as dirty.
-			uffs_Perror(UFFS_ERR_NORMAL, "unclean page found, block %d page %d", bc->block, page);
-			uffs_FlashMarkDirtyPage(dev, bc->block, page);
-		}
-	}
-
-	return U_SUCC;
-}
-
-
-static URET _BuildTreeStepOne(uffs_Device *dev)
-{
-	int block_lt;
-	uffs_BlockInfo *bc;
-	TreeNode *node;
-	struct uffs_TreeSt *tree;
-	uffs_Pool *pool;
-	struct uffs_MiniHeaderSt header;
-	URET ret = U_SUCC;
-	struct BlockTypeStatSt st = {0};
-	
-	tree = &(dev->tree);
-	pool = TPOOL(dev);
-
-	tree->bad = NULL;
-	tree->bad_count = 0;
-	tree->erased = NULL;
-	tree->erased_tail = NULL;
-	tree->erased_count = 0;
-
-	uffs_Perror(UFFS_ERR_NOISY, "build tree step one");
-
-//	printf("s:%d e:%d\n", dev->par.start, dev->par.end);
-	for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) {
-		bc = uffs_BlockInfoGet(dev, block_lt);
-//		uffs_Perror(UFFS_ERR_NORMAL, "loop");
-		if (bc == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "step one:fail to get block info");
-			ret = U_FAIL;
-			break;
-		}
-		node = (TreeNode *)uffs_PoolGet(pool);
-		if (node == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "insufficient tree node!");
-			ret = U_FAIL;
-			break;
-		}
-
-		//Need to check bad block at first !
-		if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) {
-			node->u.list.block = block_lt;
-			uffs_TreeInsertToBadBlockList(dev, node);
-			uffs_Perror(UFFS_ERR_NORMAL, "found bad block %d", block_lt);
-		}
-		else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0
-			//just need to check page 0 to know whether the block is erased
-			// Check the mini header status
-
-			if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) {
-				uffs_Perror(UFFS_ERR_SERIOUS, "I/O error when reading mini header ! block %d page %d", block_lt, 0);
-				ret = U_FAIL;
-				break;
-			}
-
-			if (header.status != 0xFF) {
-				// page 0 spare is clean but page data is dirty ??? this block should be erased immediately !
-				uffs_FlashEraseBlock(dev, block_lt);
-			}
-			node->u.list.block = block_lt;
-			if (HAVE_BADBLOCK(dev)) {
-				uffs_Perror(UFFS_ERR_NORMAL, "New bad block (%d) discovered.", block_lt);
-				uffs_BadBlockProcess(dev, node);
-			}
-			else {
-				uffs_TreeInsertToErasedListTail(dev, node);
-			}
-		}
-		else {
-
-			ret = _ScanAndFixUnCleanPage(dev, bc);
-			if (ret == U_FAIL)
-				break;
-
-			ret = _BuildValidTreeNode(dev, node, bc, &st);
-			//uffs_Perror(UFFS_ERR_NOISY, "valid block done!");
-			if (ret == U_FAIL)
-				break;
-
-		}
-		uffs_BlockInfoPut(dev, bc);
-	} //end of for
-
-	if(ret == U_FAIL) 
-		uffs_BlockInfoPut(dev, bc);
-
-	uffs_Perror(UFFS_ERR_NORMAL, "DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data);
-
-	return ret;
-}
-
-static URET _BuildTreeStepTwo(uffs_Device *dev)
-{
-	//Random the start point of erased block to implement ware leveling
-	u32 startCount = 0;
-	u32 endPoint;
-	TreeNode *node;
-
-	uffs_Perror(UFFS_ERR_NOISY, "build tree step two");
-
-	endPoint = uffs_GetCurDateTime() % dev->tree.erased_count;
-	while (startCount < endPoint) {
-		node = uffs_TreeGetErasedNode(dev);
-		if (node == NULL) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "No erased block ?");
-			return U_FAIL;
-		}
-		uffs_TreeInsertToErasedListTail(dev, node);
-		startCount++;
-	}
-
-	return U_SUCC;
-}
-
-TreeNode * uffs_TreeFindFileNode(uffs_Device *dev, u16 serial)
-{
-	int hash;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-
-	hash = serial & FILE_NODE_HASH_MASK;
-	x = tree->file_entry[hash];
-	while (x != EMPTY_NODE) {
-		node = FROM_IDX(x, TPOOL(dev));
-		if (node->u.file.serial == serial) {
-			return node;
-		}
-		else {
-			x = node->hash_next;
-		}
-	}
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindFileNodeWithParent(uffs_Device *dev, u16 parent)
-{
-	int hash;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-
-	for (hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
-		x = tree->file_entry[hash];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.file.parent == parent) {
-				return node;
-			}
-			else {
-				x = node->hash_next;
-			}
-		}
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial)
-{
-	int hash;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-
-	hash = serial & DIR_NODE_HASH_MASK;
-	x = tree->dir_entry[hash];
-	while (x != EMPTY_NODE) {
-		node = FROM_IDX(x, TPOOL(dev));
-		if (node->u.dir.serial == serial) {
-			return node;
-		}
-		else {
-			x = node->hash_next;
-		}
-	}
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent)
-{
-	int hash;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-
-	for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
-		x = tree->dir_entry[hash];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.dir.parent == parent) {
-				return node;
-			}
-			else {
-				x = node->hash_next;
-			}
-		}
-	}
-	
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent)
-{
-	int i;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	
-	for (i = 0; i < FILE_NODE_ENTRY_LEN; i++) {
-		x = tree->file_entry[i];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.file.checksum == sum && node->u.file.parent == parent) {
-				//read file name from flash, and compare...
-				if (uffs_TreeCompareFileName(dev, name, len, sum, node, UFFS_TYPE_FILE) == U_TRUE) {
-					//Got it!
-					return node;
-				}
-			}
-			x = node->hash_next;
-		}
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial)
-{
-	int hash;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	u16 x;
-
-	hash = GET_DATA_HASH(parent, serial);
-	x = tree->data_entry[hash];
-	while(x != EMPTY_NODE) {
-		node = FROM_IDX(x, TPOOL(dev));
-
-		if(node->u.data.parent == parent &&
-			node->u.data.serial == serial)
-				return node;
-
-		x = node->hash_next;
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindDirNodeByBlock(uffs_Device *dev, u16 block)
-{
-	int hash;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	u16 x;
-
-	for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
-		x = tree->dir_entry[hash];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.dir.block == block)
-				return node;
-			x = node->hash_next;
-		}
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindErasedNodeByBlock(uffs_Device *dev, u16 block)
-{
-	TreeNode *node;
-	node = dev->tree.erased;
-
-	while (node) {
-		if (node->u.list.block == block) 
-			return node;
-		node = node->u.list.next;
-	}
-		
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindBadNodeByBlock(uffs_Device *dev, u16 block)
-{
-	TreeNode *node;
-	node = dev->tree.bad;
-
-	while (node) {
-		if (node->u.list.block == block) 
-			return node;
-		node = node->u.list.next;
-	}
-		
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindFileNodeByBlock(uffs_Device *dev, u16 block)
-{
-	int hash;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	u16 x;
-
-	for (hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
-		x = tree->file_entry[hash];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.file.block == block)
-				return node;
-			x = node->hash_next;
-		}
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block)
-{
-	int hash;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	u16 x;
-
-	for (hash = 0; hash < DATA_NODE_ENTRY_LEN; hash++) {
-		x = tree->data_entry[hash];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.data.block == block)
-				return node;
-			x = node->hash_next;
-		}
-	}
-
-	return NULL;
-}
-
-TreeNode * uffs_TreeFindNodeByBlock(uffs_Device *dev, u16 block, int *region)
-{
-	TreeNode *node = NULL;
-
-	if (*region & SEARCH_REGION_DATA) {
-		node = uffs_TreeFindDataNodeByBlock(dev, block);
-		if (node) {
-			*region &= SEARCH_REGION_DATA;
-			return node;
-		}
-	}
-	if (*region & SEARCH_REGION_FILE) {
-		node = uffs_TreeFindFileNodeByBlock(dev, block);
-		if (node) {
-			*region &= SEARCH_REGION_FILE;
-			return node;
-		}
-	}
-	if (*region & SEARCH_REGION_DIR) {
-		node = uffs_TreeFindDirNodeByBlock(dev, block);
-		if (node) {
-			*region &= SEARCH_REGION_DIR;
-			return node;
-		}
-	}
-	if (*region & SEARCH_REGION_ERASED) {
-		node = uffs_TreeFindErasedNodeByBlock(dev, block);
-		if (node) {
-			*region &= SEARCH_REGION_ERASED;
-			return node;
-		}
-	}
-	if (*region & SEARCH_REGION_BAD) {
-		node = uffs_TreeFindBadNodeByBlock(dev, block);
-		if (node) {
-			*region &= SEARCH_REGION_BAD;
-			return node;
-		}
-	}
-
-	return node;
-}
-
-TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent)
-{
-	int i;
-	u16 x;
-	TreeNode *node;
-	struct uffs_TreeSt *tree = &(dev->tree);
-	
-	for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) {
-		x = tree->dir_entry[i];
-		while (x != EMPTY_NODE) {
-			node = FROM_IDX(x, TPOOL(dev));
-			if (node->u.dir.checksum == sum && node->u.dir.parent == parent) {
-				//read file name from flash, and compare...
-				if (uffs_TreeCompareFileName(dev, name, len, sum, node, UFFS_TYPE_DIR) == U_TRUE) {
-					//Got it!
-					return node;
-				}
-			}
-			x = node->hash_next;
-		}
-	}
-
-	return NULL;
-
-}
-
-UBOOL uffs_CompareFileName(const char *src, int src_len, const char *des)
-{
-	while (src_len-- > 0) {
-		if(*src++ != *des++)
-			return U_FALSE;
-	}
-
-	return U_TRUE;
-}
-
-/** compare [name] with tree [node] represented object name by loading uffs_FileInfo from storage */
-UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type)
-{
-	UBOOL matched = U_FALSE;
-	uffs_FileInfo *fi;
-	uffs_Buf *buf;
-	u16 data_sum;
-
-	buf = uffs_BufGetEx(dev, type, node, 0);
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "can't get buf !\n ");
-		goto ext;
-	}
-	fi = (uffs_FileInfo *)(buf->data);
-	data_sum = uffs_MakeSum16(fi->name, fi->name_len);
-
-	if (data_sum != sum) {
-		uffs_Perror(UFFS_ERR_NORMAL, "the obj's sum in storage is different with given sum!");
-		goto ext;
-	}
-
-	if (fi->name_len == len) {
-		if(uffs_CompareFileName(fi->name, fi->name_len, name) == U_TRUE) {
-			matched = U_TRUE;
-		}
-	}
-ext:
-	if (buf)
-		uffs_BufPut(dev, buf);
-
-	return matched;
-}
-
-
-/* calculate file length, etc */
-static URET _BuildTreeStepThree(uffs_Device *dev)
-{
-	int i;
-	u16 x;
-	TreeNode *work;
-	TreeNode *node;
-	struct uffs_TreeSt *tree;
-	uffs_Pool *pool;
-	u16 blockSave;
-
-	TreeNode *cache = NULL;
-	u16 cacheSerial = INVALID_UFFS_SERIAL;
-
-
-	tree = &(dev->tree);
-	pool = TPOOL(dev);
-
-	uffs_Perror(UFFS_ERR_NOISY, "build tree step three");
-
-	for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) {
-		x = tree->data_entry[i];
-		while (x != EMPTY_NODE) {
-			work = FROM_IDX(x, pool);
-			if (work->u.data.parent == cacheSerial) {
-				node = cache;
-			}
-			else {
-				node = uffs_TreeFindFileNode(dev, work->u.data.parent);
-				cache = node;
-				cacheSerial = work->u.data.parent;
-			}
-			if (node == NULL) {
-				x = work->hash_next;
-				//this data block does not belong to any file ?
-				//should be erased.
-				uffs_Perror(UFFS_ERR_NORMAL, "find a orphan data block:%d, parent:%d, serial:%d, will be erased!", 
-					work->u.data.block, work->u.data.parent, work->u.data.serial);
-
-				uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, work);
-				blockSave = work->u.data.block;
-				work->u.list.block = blockSave;
-				uffs_FlashEraseBlock(dev, blockSave);
-				if (HAVE_BADBLOCK(dev))
-					uffs_BadBlockProcess(dev, work);
-				else
-					uffs_TreeInsertToErasedListTail(dev, work);
-			}
-			else {
-				node->u.file.len += work->u.data.len;
-				x = work->hash_next;
-			}
-		}
-	}
-
-	return U_SUCC;
-}
-
-/** 
- * \brief build tree structure from flash
- * \param[in] dev uffs device
- */
-URET uffs_BuildTree(uffs_Device *dev)
-{
-	URET ret;
-
-	/***** step one: scan all page spares, classify DIR/FILE/DATA nodes,
-			check bad blocks/uncompleted(conflicted) blocks as well *****/
-	/* if the disk is big and full filled of data this step could be the most time consuming .... */
-	ret = _BuildTreeStepOne(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step one fail!");
-		return ret;
-	}
-
-	/***** step two: randomize the erased blocks, for ware-leveling purpose *****/
-	/* this step is very fast :) */
-	ret = _BuildTreeStepTwo(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step two fail!");
-		return ret;
-	}
-
-	/***** step three: check DATA nodes, find orphan nodes and erase them *****/
-	/* if there are a lot of files and disk is fully filled, this step could be very time consuming ... */
-	ret = _BuildTreeStepThree(dev);
-	if (ret != U_SUCC) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step three fail!");
-		return ret;
-	}
-	
-	return U_SUCC;
-}
-
-/** 
- * find a free file or dir serial NO
- * \param[in] dev uffs device
- * \return if no free serial found, return #INVALID_UFFS_SERIAL
- */
-u16 uffs_FindFreeFsnSerial(uffs_Device *dev)
-{
-	u16 i;
-	TreeNode *node;
-
-	//TODO!! Do we need a faster serial number generating method?
-	//		 it depends on how often creating files or directories
-
-	for (i = ROOT_DIR_SERIAL + 1; i < MAX_UFFS_FSN; i++) {
-		node = uffs_TreeFindDirNode(dev, i);
-		if (node == NULL) {
-			node = uffs_TreeFindFileNode(dev, i);
-			if (node == NULL)
-				return i;
-		}
-	}
-	return INVALID_UFFS_SERIAL;
-}
-
-TreeNode * uffs_TreeGetErasedNode(uffs_Device *dev)
-{
-	TreeNode *node = NULL;
-	if (dev->tree.erased) {
-		node = dev->tree.erased;
-		dev->tree.erased->u.list.prev = NULL;
-		dev->tree.erased = dev->tree.erased->u.list.next;
-		if(dev->tree.erased == NULL) 
-			dev->tree.erased_tail = NULL;
-		dev->tree.erased_count--;
-	}
-	
-	return node;
-}
-
-static void _InsertToEntry(uffs_Device *dev, u16 *entry, int hash, TreeNode *node)
-{
-	struct uffs_TreeSt *tree = &(dev->tree);
-
-	node->hash_next = entry[hash];
-#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
-	node->hash_prev = EMPTY_NODE;
-	if (entry[hash] != EMPTY_NODE) {
-		FROM_IDX(entry[hash], TPOOL(dev))->hash_prev = TO_IDX(node, TPOOL(dev));
-	}
-#endif
-	entry[hash] = TO_IDX(node, TPOOL(dev));
-}
-
-
-#ifndef CONFIG_TREE_NODE_USE_DOUBLE_LINK
-TreeNode * _FindPrevNodeFromEntry(uffs_Device *dev, u16 start, u16 find)
-{
-	TreeNode *work;
-	while (start != EMPTY_NODE) {
-		work = FROM_IDX(start, &(dev->mem.tree_pool));
-		if (work->hash_next == find) {
-			return work;
-		}
-	}
-	return NULL;
-}
-#endif
-
-/** 
- * break the node from entry
- */
-void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node)
-{
-	u16 *entry;
-	int hash;
-	TreeNode *work;
-
-	switch (type) {
-	case UFFS_TYPE_DIR:
-		hash = GET_DIR_HASH(node->u.dir.serial);
-		entry = &(dev->tree.dir_entry[hash]);
-		break;
-	case UFFS_TYPE_FILE:
-		hash = GET_FILE_HASH(node->u.file.serial);
-		entry = &(dev->tree.file_entry[hash]);
-		break;
-	case UFFS_TYPE_DATA:
-		hash = GET_DATA_HASH(node->u.data.parent, node->u.data.serial);
-		entry = &(dev->tree.data_entry[hash]);
-		break;
-	default:
-		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type when break...");
-		return;
-	}
-#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
-	if (node->hash_prev != EMPTY_NODE) {
-		work = FROM_IDX(node->hash_prev, &(dev->mem.tree_pool));
-		work->hash_next = node->hash_next;
-	}
-	if (node->hash_next != EMPTY_NODE) {
-		work = FROM_IDX(node->hash_next, &(dev->mem.tree_pool));
-		work->hash_prev = node->hash_prev;
-	}
-#else
-	if ((work = _FindPrevNodeFromEntry(dev, *entry, TO_IDX(node, &(dev->mem.tree_pool)))) != NULL) {
-		work->hash_next = node->hash_next;
-	}
-#endif
-
-	if (*entry == TO_IDX(node, &(dev->mem.tree_pool))) {
-		*entry = node->hash_next;
-	}
-}
-
-static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node)
-{
-	_InsertToEntry(dev, dev->tree.file_entry, GET_FILE_HASH(node->u.file.serial), node);
-}
-
-static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node)
-{
-	_InsertToEntry(dev, dev->tree.dir_entry, GET_DIR_HASH(node->u.dir.serial), node);
-}
-
-static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node)
-{
-	_InsertToEntry(dev, dev->tree.data_entry, GET_DATA_HASH(node->u.data.parent, node->u.data.serial), node);
-}
-
-void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node)
-{
-	struct uffs_TreeSt *tree;
-	tree = &(dev->tree);
-
-	node->u.list.next = tree->erased;
-	node->u.list.prev = NULL;
-
-	if (tree->erased) {
-		tree->erased->u.list.prev = node;
-	}
-
-	tree->erased = node;
-	if (node->u.list.next == tree->erased_tail) {
-		tree->erased_tail = node;
-	}
-	tree->erased_count++;
-}
-
-void uffs_TreeInsertToErasedListTail(uffs_Device *dev, TreeNode *node)
-{
-	struct uffs_TreeSt *tree;
-	tree = &(dev->tree);
-
-	node->u.list.next = NULL;
-	node->u.list.prev = tree->erased_tail;
-	if (tree->erased_tail) {
-		tree->erased_tail->u.list.next = node;
-	}
-
-	tree->erased_tail = node;
-	if(tree->erased == NULL) {
-		tree->erased = node;
-	}
-	tree->erased_count++;
-}
-
-void uffs_TreeInsertToBadBlockList(uffs_Device *dev, TreeNode *node)
-{
-	struct uffs_TreeSt *tree;
-
-	tree = &(dev->tree);
-	node->u.list.prev = NULL;
-	node->u.list.next = tree->bad;
-
-	if (tree->bad) {
-		tree->bad->u.list.prev = node;
-	}
-
-	tree->bad = node;
-	tree->bad_count++;
-}
-
-/** 
- * set tree node block value
- */
-void uffs_TreeSetNodeBlock(u8 type, TreeNode *node, u16 block)
-{
-	switch (type) {
-	case UFFS_TYPE_FILE:
-		node->u.file.block = block;
-		break;
-	case UFFS_TYPE_DIR:
-		node->u.dir.block = block;
-		break;
-	case UFFS_TYPE_DATA:
-		node->u.data.block = block;
-		break;
-	}
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_tree.c
+ * \brief seting up uffs tree data structure
+ * \author Ricky Zheng, created 13th May, 2005
+ */
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_pool.h"
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_flash.h"
+#include "uffs/uffs_badblock.h"
+
+#include <string.h>
+
+#define TPOOL(dev) &(dev->mem.tree_pool)
+
+#define PFX "tree: "
+
+static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node);
+static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node);
+static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node);
+
+struct BlockTypeStatSt {
+	int dir;
+	int file;
+	int data;
+};
+
+/** 
+ * \brief initialize tree buffers
+ * \param[in] dev uffs device
+ */
+URET uffs_TreeInit(uffs_Device *dev)
+{
+	int size;
+	int num;
+	uffs_Pool *pool;
+	int i;
+
+	size = sizeof(TreeNode);
+	num = dev->par.end - dev->par.start + 1;
+	
+	pool = &(dev->mem.tree_pool);
+
+	if (dev->mem.tree_nodes_pool_size == 0) 
+	{
+		if (dev->mem.malloc) 
+		{
+			dev->mem.tree_nodes_pool_buf = dev->mem.malloc(dev, size * num);
+			if (dev->mem.tree_nodes_pool_buf)
+				dev->mem.tree_nodes_pool_size = size * num;
+		}
+	}
+	if (size * num > dev->mem.tree_nodes_pool_size) 
+	{
+		uffs_Perror(UFFS_ERR_DEAD, "Tree buffer require %d but only %d available.", size * num, dev->mem.tree_nodes_pool_size);
+		memset(pool, 0, sizeof(uffs_Pool));
+		return U_FAIL;
+	}
+	uffs_Perror(UFFS_ERR_NOISY, "alloc tree nodes %d bytes.", size * num);
+	
+	uffs_PoolInit(pool, dev->mem.tree_nodes_pool_buf, dev->mem.tree_nodes_pool_size, size, num);
+
+	dev->tree.erased = NULL;
+	dev->tree.erased_tail = NULL;
+	dev->tree.erased_count = 0;
+	dev->tree.bad = NULL;
+	dev->tree.bad_count = 0;
+
+	for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) 
+	{
+		dev->tree.dir_entry[i] = EMPTY_NODE;
+	}
+
+	for (i = 0; i < FILE_NODE_ENTRY_LEN; i++) 
+	{
+		dev->tree.file_entry[i] = EMPTY_NODE;
+	}
+
+	for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) 
+	{
+		dev->tree.data_entry[i] = EMPTY_NODE;
+	}
+
+	dev->tree.max_serial = ROOT_DIR_SERIAL;
+	
+	return U_SUCC;
+}
+/** 
+ * \brief release tree buffers, call this function when unmount
+ * \param[in] dev uffs device
+ */
+URET uffs_TreeRelease(uffs_Device *dev)
+{
+	uffs_Pool *pool;
+	
+	pool = &(dev->mem.tree_pool);
+	if (pool->mem && dev->mem.free) 
+	{
+		dev->mem.free(dev, pool->mem);
+		pool->mem = NULL;
+		dev->mem.tree_nodes_pool_size = 0;
+	}
+	uffs_PoolRelease(pool);
+	memset(pool, 0, sizeof(uffs_Pool));
+
+	return U_SUCC;
+}
+
+static u16 _GetBlockFromNode(u8 type, TreeNode *node)
+{
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		return node->u.dir.block;
+	case UFFS_TYPE_FILE:
+		return node->u.file.block;
+	case UFFS_TYPE_DATA:
+		return node->u.data.block;
+	}
+	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-block");
+	return UFFS_INVALID_BLOCK;
+}
+
+#if 0
+static u16 _GetParentFromNode(u8 type, TreeNode *node)
+{
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		return node->u.dir.parent;
+	case UFFS_TYPE_FILE:
+		return node->u.file.parent;
+	case UFFS_TYPE_DATA:
+		return node->u.data.parent;
+	}
+	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-parent");
+	return INVALID_UFFS_SERIAL;
+}
+
+
+static u16 _GetSerialFromNode(u8 type, TreeNode *node)
+{
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		return node->u.dir.serial;
+	case UFFS_TYPE_FILE:
+		return node->u.file.serial;
+	case UFFS_TYPE_DATA:
+		return node->u.data.serial;
+	}
+	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, X-serial");
+	return INVALID_UFFS_SERIAL;
+}
+#endif
+
+/** 
+ * insert a TreeNode *node to tree
+ * \param[in] dev uffs device
+ * \param[in] type type of node
+ * \param[in] node node to be insert to
+ */
+void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node)
+{
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		uffs_InsertToDirEntry(dev, node);
+		break;
+	case UFFS_TYPE_FILE:
+		uffs_InsertToFileEntry(dev, node);
+		break;
+	case UFFS_TYPE_DATA:
+		uffs_InsertToDataEntry(dev, node);
+		break;
+	default:
+		uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, can't insert to tree");
+		break;
+	}
+}
+
+/** 
+ * find a node from tree
+ * \param[in] dev uffs device
+ * \param[in] type type of node
+ * \param[in] parent parent serial num
+ * \param[in] serial serial num
+ */
+TreeNode * uffs_FindFromTree(uffs_Device *dev, u8 type, u16 parent, u16 serial)
+{
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		return uffs_TreeFindDirNode(dev, serial);
+	case UFFS_TYPE_FILE:
+		return uffs_TreeFindFileNode(dev, serial);
+	case UFFS_TYPE_DATA:
+		return uffs_TreeFindDataNode(dev, parent, serial);
+	}
+	uffs_Perror(UFFS_ERR_SERIOUS, "unkown type, can't find node");
+	return NULL;
+}
+
+
+
+static URET _BuildValidTreeNode(uffs_Device *dev,
+								TreeNode *node,		//!< empty node
+								uffs_BlockInfo *bc,
+								struct BlockTypeStatSt *st)
+{
+	uffs_Tags *tag;
+	TreeNode *node_alt;
+	u16 block, parent, serial, block_alt, block_save;
+	uffs_BlockInfo *bc_alt;
+	u8 type;
+	int page;
+	UBOOL needToInsertToTree = U_FALSE;
+	uffs_Buf *buf = NULL;
+	uffs_FileInfo *info;
+	u16 data_sum = 0;
+
+	// check the first page on the block ...
+	uffs_BlockInfoLoad(dev, bc, 0);
+
+	tag = GET_TAG(bc, 0);  //get first page's tag
+
+	if (!TAG_IS_DIRTY(tag)) {
+		uffs_Perror(UFFS_ERR_NORMAL, "First page is clean in a non-erased block ?");
+		return U_FAIL;
+	}
+
+	if (!TAG_IS_VALID(tag)) {
+		//first page is invalid ? should be erased now!
+		uffs_Perror(UFFS_ERR_NORMAL, "first page in block %d is invalid, will be erased now!", bc->block);
+		goto process_invalid_block;		
+	}
+
+	block = bc->block;
+	parent = TAG_PARENT(tag);
+	serial = TAG_SERIAL(tag);
+	type = TAG_TYPE(tag);
+
+	// check if there is an 'alternative block' (node which has the same serial number) in tree ?
+	node_alt = uffs_FindFromTree(dev, type, parent, serial); 
+
+	if (node_alt != NULL) {
+		//find a alternate node ! need to check the timestamp !
+
+		block_alt = _GetBlockFromNode(type, node_alt);
+
+		uffs_Perror(UFFS_ERR_NORMAL, "Process unclean block (%d vs %d)", block, block_alt);
+
+		if (block_alt == INVALID_UFFS_SERIAL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "invalid block ?");
+			return U_FAIL;
+		}
+		
+		bc_alt = uffs_BlockInfoGet(dev, block_alt);
+		if (bc_alt == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "can't get block info ");
+			return U_FAIL;
+		}
+		uffs_BlockInfoLoad(dev, bc_alt, 0);
+		if (uffs_IsSrcNewerThanObj (
+				TAG_BLOCK_TS(tag),
+				TAG_BLOCK_TS(GET_TAG(bc_alt, 0))) == U_TRUE) {
+
+			//the node is newer than node_alt, so keep node_alt, and erase node
+			uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+			uffs_FlashEraseBlock(dev, block);
+			node->u.list.block = block;
+			if (HAVE_BADBLOCK(dev))
+				uffs_BadBlockProcess(dev, node);
+			else
+				uffs_TreeInsertToErasedListTail(dev, node);
+
+			uffs_BlockInfoPut(dev, bc_alt);  //put back bc_alt before we return.
+			return U_SUCC;
+		}
+		else {
+			//the node is older than node_alt, so keep node, and erase node_alt
+			//we use node as erased node to insert to erased list
+
+			block_save = _GetBlockFromNode(type, node_alt);
+			uffs_FlashEraseBlock(dev, block_save);
+			uffs_BlockInfoExpire(dev, bc_alt, UFFS_ALL_PAGES);
+			node->u.list.block = block_save;
+			if (HAVE_BADBLOCK(dev))
+				uffs_BadBlockProcess(dev, node);
+			else
+				uffs_TreeInsertToErasedListTail(dev, node);
+
+			uffs_BlockInfoPut(dev, bc_alt);  //put back bc_alt because we don't need it anymore.
+			
+			node = node_alt;	//use node_alt to store new informations in following
+			needToInsertToTree = U_FALSE;
+		}
+	}
+	else {
+		needToInsertToTree = U_TRUE;
+	}
+
+	if (type == UFFS_TYPE_DIR || type == UFFS_TYPE_FILE) {
+		buf = uffs_BufClone(dev, NULL);
+		if (buf == NULL)
+			return U_FAIL;
+		uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
+		page = uffs_FindPageInBlockWithPageId(dev, bc, 0);
+		if (page == UFFS_INVALID_PAGE) {
+			uffs_BufFreeClone(dev, buf);
+			uffs_Perror(UFFS_ERR_SERIOUS, "Can't find any valid page for page_id=0 ? invalid block !"
+												"this might be caused by the tag layout change.\n");
+			goto process_invalid_block;
+		}
+		page = uffs_FindBestPageInBlock(dev, bc, page);
+		uffs_FlashReadPage(dev, block, page, buf);
+		info = (uffs_FileInfo *) (buf->data);
+		data_sum = uffs_MakeSum16(info->name, info->name_len);
+		uffs_BufFreeClone(dev, buf);
+	}
+
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		node->u.dir.block = bc->block;
+		node->u.dir.checksum = data_sum;
+		node->u.dir.parent = TAG_PARENT(tag);
+		node->u.dir.serial = TAG_SERIAL(tag);
+		st->dir++;
+		break;
+	case UFFS_TYPE_FILE:
+		node->u.file.block = bc->block;
+		node->u.file.checksum = data_sum;
+		node->u.file.parent = TAG_PARENT(tag);
+		node->u.file.serial = TAG_SERIAL(tag);
+		node->u.file.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_FILE);  
+		st->file++;
+		break;
+	case UFFS_TYPE_DATA:
+		node->u.data.block = bc->block;
+		node->u.data.parent = TAG_PARENT(tag);
+		node->u.data.serial = TAG_SERIAL(tag);
+		node->u.data.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_DATA); 
+		st->data++;
+		break;
+	}
+
+	if (needToInsertToTree == U_TRUE) {
+		uffs_InsertNodeToTree(dev, type, node);
+	}
+
+	return U_SUCC;
+
+process_invalid_block:
+	/* erase the invalid block */
+	uffs_FlashEraseBlock(dev, bc->block);
+	uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
+
+	node->u.list.block = bc->block;
+	if (HAVE_BADBLOCK(dev))
+		uffs_BadBlockProcess(dev, node);
+	else
+		uffs_TreeInsertToErasedListTail(dev, node);
+
+	return U_SUCC;
+}
+
+
+static URET _ScanAndFixUnCleanPage(uffs_Device *dev, uffs_BlockInfo *bc)
+{
+	int page;
+	uffs_Tags *tag;
+	struct uffs_MiniHeaderSt header;
+
+	/* in most case, the valid block contents fewer free page,
+		so it's better scan from the last page ... to page 1.
+		note: scaning page 0 is not necessary.
+
+		The worse case: read (pages_per_block - 1) * (mini header + spares) !
+		most case: read one spare.
+	*/
+	for (page = dev->attr->pages_per_block - 1; page > 0; page--) {
+		uffs_BlockInfoLoad(dev, bc, page);
+		tag = GET_TAG(bc, page);
+		if (TAG_IS_DIRTY(tag) || TAG_IS_VALID(tag))  // stop if we reach a dirty or valid page
+			break;
+
+		if (uffs_LoadMiniHeader(dev, bc->block, page, &header) == U_FAIL)
+			return U_FAIL;
+
+		if (header.status != 0xFF) {
+			// ok, page data is not clean ! mark it as dirty.
+			uffs_Perror(UFFS_ERR_NORMAL, "unclean page found, block %d page %d", bc->block, page);
+			uffs_FlashMarkDirtyPage(dev, bc->block, page);
+		}
+	}
+
+	return U_SUCC;
+}
+
+
+static URET _BuildTreeStepOne(uffs_Device *dev)
+{
+	int block_lt;
+	uffs_BlockInfo *bc;
+	TreeNode *node;
+	struct uffs_TreeSt *tree;
+	uffs_Pool *pool;
+	struct uffs_MiniHeaderSt header;
+	URET ret = U_SUCC;
+	struct BlockTypeStatSt st = {0};
+	
+	tree = &(dev->tree);
+	pool = TPOOL(dev);
+
+	tree->bad = NULL;
+	tree->bad_count = 0;
+	tree->erased = NULL;
+	tree->erased_tail = NULL;
+	tree->erased_count = 0;
+
+	uffs_Perror(UFFS_ERR_NOISY, "build tree step one");
+
+//	printf("s:%d e:%d\n", dev->par.start, dev->par.end);
+	for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) {
+		bc = uffs_BlockInfoGet(dev, block_lt);
+//		uffs_Perror(UFFS_ERR_NORMAL, "loop");
+		if (bc == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "step one:fail to get block info");
+			ret = U_FAIL;
+			break;
+		}
+		node = (TreeNode *)uffs_PoolGet(pool);
+		if (node == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "insufficient tree node!");
+			ret = U_FAIL;
+			break;
+		}
+
+		//Need to check bad block at first !
+		if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) {
+			node->u.list.block = block_lt;
+			uffs_TreeInsertToBadBlockList(dev, node);
+			uffs_Perror(UFFS_ERR_NORMAL, "found bad block %d", block_lt);
+		}
+		else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0
+			//just need to check page 0 to know whether the block is erased
+			// Check the mini header status
+
+			if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) {
+				uffs_Perror(UFFS_ERR_SERIOUS, "I/O error when reading mini header ! block %d page %d", block_lt, 0);
+				ret = U_FAIL;
+				break;
+			}
+
+			if (header.status != 0xFF) {
+				// page 0 spare is clean but page data is dirty ??? this block should be erased immediately !
+				uffs_FlashEraseBlock(dev, block_lt);
+			}
+			node->u.list.block = block_lt;
+			if (HAVE_BADBLOCK(dev)) {
+				uffs_Perror(UFFS_ERR_NORMAL, "New bad block (%d) discovered.", block_lt);
+				uffs_BadBlockProcess(dev, node);
+			}
+			else {
+				uffs_TreeInsertToErasedListTail(dev, node);
+			}
+		}
+		else {
+
+			ret = _ScanAndFixUnCleanPage(dev, bc);
+			if (ret == U_FAIL)
+				break;
+
+			ret = _BuildValidTreeNode(dev, node, bc, &st);
+			//uffs_Perror(UFFS_ERR_NOISY, "valid block done!");
+			if (ret == U_FAIL)
+				break;
+
+		}
+		uffs_BlockInfoPut(dev, bc);
+	} //end of for
+
+	if(ret == U_FAIL) 
+		uffs_BlockInfoPut(dev, bc);
+
+	uffs_Perror(UFFS_ERR_NORMAL, "DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data);
+
+	return ret;
+}
+
+static URET _BuildTreeStepTwo(uffs_Device *dev)
+{
+	//Random the start point of erased block to implement ware leveling
+	u32 startCount = 0;
+	u32 endPoint;
+	TreeNode *node;
+
+	uffs_Perror(UFFS_ERR_NOISY, "build tree step two");
+
+	endPoint = uffs_GetCurDateTime() % dev->tree.erased_count;
+	while (startCount < endPoint) {
+		node = uffs_TreeGetErasedNode(dev);
+		if (node == NULL) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "No erased block ?");
+			return U_FAIL;
+		}
+		uffs_TreeInsertToErasedListTail(dev, node);
+		startCount++;
+	}
+
+	return U_SUCC;
+}
+
+TreeNode * uffs_TreeFindFileNode(uffs_Device *dev, u16 serial)
+{
+	int hash;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+
+	hash = serial & FILE_NODE_HASH_MASK;
+	x = tree->file_entry[hash];
+	while (x != EMPTY_NODE) {
+		node = FROM_IDX(x, TPOOL(dev));
+		if (node->u.file.serial == serial) {
+			return node;
+		}
+		else {
+			x = node->hash_next;
+		}
+	}
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindFileNodeWithParent(uffs_Device *dev, u16 parent)
+{
+	int hash;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+
+	for (hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
+		x = tree->file_entry[hash];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.file.parent == parent) {
+				return node;
+			}
+			else {
+				x = node->hash_next;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial)
+{
+	int hash;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+
+	hash = serial & DIR_NODE_HASH_MASK;
+	x = tree->dir_entry[hash];
+	while (x != EMPTY_NODE) {
+		node = FROM_IDX(x, TPOOL(dev));
+		if (node->u.dir.serial == serial) {
+			return node;
+		}
+		else {
+			x = node->hash_next;
+		}
+	}
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent)
+{
+	int hash;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+
+	for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
+		x = tree->dir_entry[hash];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.dir.parent == parent) {
+				return node;
+			}
+			else {
+				x = node->hash_next;
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent)
+{
+	int i;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	
+	for (i = 0; i < FILE_NODE_ENTRY_LEN; i++) {
+		x = tree->file_entry[i];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.file.checksum == sum && node->u.file.parent == parent) {
+				//read file name from flash, and compare...
+				if (uffs_TreeCompareFileName(dev, name, len, sum, node, UFFS_TYPE_FILE) == U_TRUE) {
+					//Got it!
+					return node;
+				}
+			}
+			x = node->hash_next;
+		}
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial)
+{
+	int hash;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	u16 x;
+
+	hash = GET_DATA_HASH(parent, serial);
+	x = tree->data_entry[hash];
+	while(x != EMPTY_NODE) {
+		node = FROM_IDX(x, TPOOL(dev));
+
+		if(node->u.data.parent == parent &&
+			node->u.data.serial == serial)
+				return node;
+
+		x = node->hash_next;
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindDirNodeByBlock(uffs_Device *dev, u16 block)
+{
+	int hash;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	u16 x;
+
+	for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
+		x = tree->dir_entry[hash];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.dir.block == block)
+				return node;
+			x = node->hash_next;
+		}
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindErasedNodeByBlock(uffs_Device *dev, u16 block)
+{
+	TreeNode *node;
+	node = dev->tree.erased;
+
+	while (node) {
+		if (node->u.list.block == block) 
+			return node;
+		node = node->u.list.next;
+	}
+		
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindBadNodeByBlock(uffs_Device *dev, u16 block)
+{
+	TreeNode *node;
+	node = dev->tree.bad;
+
+	while (node) {
+		if (node->u.list.block == block) 
+			return node;
+		node = node->u.list.next;
+	}
+		
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindFileNodeByBlock(uffs_Device *dev, u16 block)
+{
+	int hash;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	u16 x;
+
+	for (hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
+		x = tree->file_entry[hash];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.file.block == block)
+				return node;
+			x = node->hash_next;
+		}
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block)
+{
+	int hash;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	u16 x;
+
+	for (hash = 0; hash < DATA_NODE_ENTRY_LEN; hash++) {
+		x = tree->data_entry[hash];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.data.block == block)
+				return node;
+			x = node->hash_next;
+		}
+	}
+
+	return NULL;
+}
+
+TreeNode * uffs_TreeFindNodeByBlock(uffs_Device *dev, u16 block, int *region)
+{
+	TreeNode *node = NULL;
+
+	if (*region & SEARCH_REGION_DATA) {
+		node = uffs_TreeFindDataNodeByBlock(dev, block);
+		if (node) {
+			*region &= SEARCH_REGION_DATA;
+			return node;
+		}
+	}
+	if (*region & SEARCH_REGION_FILE) {
+		node = uffs_TreeFindFileNodeByBlock(dev, block);
+		if (node) {
+			*region &= SEARCH_REGION_FILE;
+			return node;
+		}
+	}
+	if (*region & SEARCH_REGION_DIR) {
+		node = uffs_TreeFindDirNodeByBlock(dev, block);
+		if (node) {
+			*region &= SEARCH_REGION_DIR;
+			return node;
+		}
+	}
+	if (*region & SEARCH_REGION_ERASED) {
+		node = uffs_TreeFindErasedNodeByBlock(dev, block);
+		if (node) {
+			*region &= SEARCH_REGION_ERASED;
+			return node;
+		}
+	}
+	if (*region & SEARCH_REGION_BAD) {
+		node = uffs_TreeFindBadNodeByBlock(dev, block);
+		if (node) {
+			*region &= SEARCH_REGION_BAD;
+			return node;
+		}
+	}
+
+	return node;
+}
+
+TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent)
+{
+	int i;
+	u16 x;
+	TreeNode *node;
+	struct uffs_TreeSt *tree = &(dev->tree);
+	
+	for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) {
+		x = tree->dir_entry[i];
+		while (x != EMPTY_NODE) {
+			node = FROM_IDX(x, TPOOL(dev));
+			if (node->u.dir.checksum == sum && node->u.dir.parent == parent) {
+				//read file name from flash, and compare...
+				if (uffs_TreeCompareFileName(dev, name, len, sum, node, UFFS_TYPE_DIR) == U_TRUE) {
+					//Got it!
+					return node;
+				}
+			}
+			x = node->hash_next;
+		}
+	}
+
+	return NULL;
+
+}
+
+UBOOL uffs_CompareFileName(const char *src, int src_len, const char *des)
+{
+	while (src_len-- > 0) {
+		if(*src++ != *des++)
+			return U_FALSE;
+	}
+
+	return U_TRUE;
+}
+
+/** compare [name] with tree [node] represented object name by loading uffs_FileInfo from storage */
+UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type)
+{
+	UBOOL matched = U_FALSE;
+	uffs_FileInfo *fi;
+	uffs_Buf *buf;
+	u16 data_sum;
+
+	buf = uffs_BufGetEx(dev, type, node, 0);
+	if (buf == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "can't get buf !\n ");
+		goto ext;
+	}
+	fi = (uffs_FileInfo *)(buf->data);
+	data_sum = uffs_MakeSum16(fi->name, fi->name_len);
+
+	if (data_sum != sum) {
+		uffs_Perror(UFFS_ERR_NORMAL, "the obj's sum in storage is different with given sum!");
+		goto ext;
+	}
+
+	if (fi->name_len == len) {
+		if(uffs_CompareFileName(fi->name, fi->name_len, name) == U_TRUE) {
+			matched = U_TRUE;
+		}
+	}
+ext:
+	if (buf)
+		uffs_BufPut(dev, buf);
+
+	return matched;
+}
+
+
+/* calculate file length, etc */
+static URET _BuildTreeStepThree(uffs_Device *dev)
+{
+	int i;
+	u16 x;
+	TreeNode *work;
+	TreeNode *node;
+	struct uffs_TreeSt *tree;
+	uffs_Pool *pool;
+	u16 blockSave;
+
+	TreeNode *cache = NULL;
+	u16 cacheSerial = INVALID_UFFS_SERIAL;
+
+
+	tree = &(dev->tree);
+	pool = TPOOL(dev);
+
+	uffs_Perror(UFFS_ERR_NOISY, "build tree step three");
+
+	for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) {
+		x = tree->data_entry[i];
+		while (x != EMPTY_NODE) {
+			work = FROM_IDX(x, pool);
+			if (work->u.data.parent == cacheSerial) {
+				node = cache;
+			}
+			else {
+				node = uffs_TreeFindFileNode(dev, work->u.data.parent);
+				cache = node;
+				cacheSerial = work->u.data.parent;
+			}
+			if (node == NULL) {
+				x = work->hash_next;
+				//this data block does not belong to any file ?
+				//should be erased.
+				uffs_Perror(UFFS_ERR_NORMAL, "find a orphan data block:%d, parent:%d, serial:%d, will be erased!", 
+					work->u.data.block, work->u.data.parent, work->u.data.serial);
+
+				uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, work);
+				blockSave = work->u.data.block;
+				work->u.list.block = blockSave;
+				uffs_FlashEraseBlock(dev, blockSave);
+				if (HAVE_BADBLOCK(dev))
+					uffs_BadBlockProcess(dev, work);
+				else
+					uffs_TreeInsertToErasedListTail(dev, work);
+			}
+			else {
+				node->u.file.len += work->u.data.len;
+				x = work->hash_next;
+			}
+		}
+	}
+
+	return U_SUCC;
+}
+
+/** 
+ * \brief build tree structure from flash
+ * \param[in] dev uffs device
+ */
+URET uffs_BuildTree(uffs_Device *dev)
+{
+	URET ret;
+
+	/***** step one: scan all page spares, classify DIR/FILE/DATA nodes,
+			check bad blocks/uncompleted(conflicted) blocks as well *****/
+	/* if the disk is big and full filled of data this step could be the most time consuming .... */
+	ret = _BuildTreeStepOne(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step one fail!");
+		return ret;
+	}
+
+	/***** step two: randomize the erased blocks, for ware-leveling purpose *****/
+	/* this step is very fast :) */
+	ret = _BuildTreeStepTwo(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step two fail!");
+		return ret;
+	}
+
+	/***** step three: check DATA nodes, find orphan nodes and erase them *****/
+	/* if there are a lot of files and disk is fully filled, this step could be very time consuming ... */
+	ret = _BuildTreeStepThree(dev);
+	if (ret != U_SUCC) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "build tree step three fail!");
+		return ret;
+	}
+	
+	return U_SUCC;
+}
+
+/** 
+ * find a free file or dir serial NO
+ * \param[in] dev uffs device
+ * \return if no free serial found, return #INVALID_UFFS_SERIAL
+ */
+u16 uffs_FindFreeFsnSerial(uffs_Device *dev)
+{
+	u16 i;
+	TreeNode *node;
+
+	//TODO!! Do we need a faster serial number generating method?
+	//		 it depends on how often creating files or directories
+
+	for (i = ROOT_DIR_SERIAL + 1; i < MAX_UFFS_FSN; i++) {
+		node = uffs_TreeFindDirNode(dev, i);
+		if (node == NULL) {
+			node = uffs_TreeFindFileNode(dev, i);
+			if (node == NULL)
+				return i;
+		}
+	}
+	return INVALID_UFFS_SERIAL;
+}
+
+TreeNode * uffs_TreeGetErasedNode(uffs_Device *dev)
+{
+	TreeNode *node = NULL;
+	if (dev->tree.erased) {
+		node = dev->tree.erased;
+		dev->tree.erased->u.list.prev = NULL;
+		dev->tree.erased = dev->tree.erased->u.list.next;
+		if(dev->tree.erased == NULL) 
+			dev->tree.erased_tail = NULL;
+		dev->tree.erased_count--;
+	}
+	
+	return node;
+}
+
+static void _InsertToEntry(uffs_Device *dev, u16 *entry, int hash, TreeNode *node)
+{
+	/* struct uffs_TreeSt *tree = &(dev->tree); */
+
+	node->hash_next = entry[hash];
+#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
+	node->hash_prev = EMPTY_NODE;
+	if (entry[hash] != EMPTY_NODE) {
+		FROM_IDX(entry[hash], TPOOL(dev))->hash_prev = TO_IDX(node, TPOOL(dev));
+	}
+#endif
+	entry[hash] = TO_IDX(node, TPOOL(dev));
+}
+
+
+#ifndef CONFIG_TREE_NODE_USE_DOUBLE_LINK
+TreeNode * _FindPrevNodeFromEntry(uffs_Device *dev, u16 start, u16 find)
+{
+	TreeNode *work;
+	while (start != EMPTY_NODE) {
+		work = FROM_IDX(start, &(dev->mem.tree_pool));
+		if (work->hash_next == find) {
+			return work;
+		}
+	}
+	return NULL;
+}
+#endif
+
+/** 
+ * break the node from entry
+ */
+void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node)
+{
+	u16 *entry;
+	int hash;
+	TreeNode *work;
+
+	switch (type) {
+	case UFFS_TYPE_DIR:
+		hash = GET_DIR_HASH(node->u.dir.serial);
+		entry = &(dev->tree.dir_entry[hash]);
+		break;
+	case UFFS_TYPE_FILE:
+		hash = GET_FILE_HASH(node->u.file.serial);
+		entry = &(dev->tree.file_entry[hash]);
+		break;
+	case UFFS_TYPE_DATA:
+		hash = GET_DATA_HASH(node->u.data.parent, node->u.data.serial);
+		entry = &(dev->tree.data_entry[hash]);
+		break;
+	default:
+		uffs_Perror(UFFS_ERR_SERIOUS, "unknown type when break...");
+		return;
+	}
+#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
+	if (node->hash_prev != EMPTY_NODE) {
+		work = FROM_IDX(node->hash_prev, &(dev->mem.tree_pool));
+		work->hash_next = node->hash_next;
+	}
+	if (node->hash_next != EMPTY_NODE) {
+		work = FROM_IDX(node->hash_next, &(dev->mem.tree_pool));
+		work->hash_prev = node->hash_prev;
+	}
+#else
+	if ((work = _FindPrevNodeFromEntry(dev, *entry, TO_IDX(node, &(dev->mem.tree_pool)))) != NULL) {
+		work->hash_next = node->hash_next;
+	}
+#endif
+
+	if (*entry == TO_IDX(node, &(dev->mem.tree_pool))) {
+		*entry = node->hash_next;
+	}
+}
+
+static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node)
+{
+	_InsertToEntry(dev, dev->tree.file_entry, GET_FILE_HASH(node->u.file.serial), node);
+}
+
+static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node)
+{
+	_InsertToEntry(dev, dev->tree.dir_entry, GET_DIR_HASH(node->u.dir.serial), node);
+}
+
+static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node)
+{
+	_InsertToEntry(dev, dev->tree.data_entry, GET_DATA_HASH(node->u.data.parent, node->u.data.serial), node);
+}
+
+void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node)
+{
+	struct uffs_TreeSt *tree;
+	tree = &(dev->tree);
+
+	node->u.list.next = tree->erased;
+	node->u.list.prev = NULL;
+
+	if (tree->erased) {
+		tree->erased->u.list.prev = node;
+	}
+
+	tree->erased = node;
+	if (node->u.list.next == tree->erased_tail) {
+		tree->erased_tail = node;
+	}
+	tree->erased_count++;
+}
+
+void uffs_TreeInsertToErasedListTail(uffs_Device *dev, TreeNode *node)
+{
+	struct uffs_TreeSt *tree;
+	tree = &(dev->tree);
+
+	node->u.list.next = NULL;
+	node->u.list.prev = tree->erased_tail;
+	if (tree->erased_tail) {
+		tree->erased_tail->u.list.next = node;
+	}
+
+	tree->erased_tail = node;
+	if(tree->erased == NULL) {
+		tree->erased = node;
+	}
+	tree->erased_count++;
+}
+
+void uffs_TreeInsertToBadBlockList(uffs_Device *dev, TreeNode *node)
+{
+	struct uffs_TreeSt *tree;
+
+	tree = &(dev->tree);
+	node->u.list.prev = NULL;
+	node->u.list.next = tree->bad;
+
+	if (tree->bad) {
+		tree->bad->u.list.prev = node;
+	}
+
+	tree->bad = node;
+	tree->bad_count++;
+}
+
+/** 
+ * set tree node block value
+ */
+void uffs_TreeSetNodeBlock(u8 type, TreeNode *node, u16 block)
+{
+	switch (type) {
+	case UFFS_TYPE_FILE:
+		node->u.file.block = block;
+		break;
+	case UFFS_TYPE_DIR:
+		node->u.dir.block = block;
+		break;
+	case UFFS_TYPE_DATA:
+		node->u.data.block = block;
+		break;
+	}
+}
+

+ 195 - 195
components/dfs/filesystems/uffs/src/uffs/uffs_utils.c

@@ -1,195 +1,195 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_utils.c
- * \brief utilities of uffs
- * \author Ricky Zheng, created 12th May, 2005
- */
-#include "uffs/uffs_device.h"
-#include "uffs/uffs_utils.h"
-#include "uffs/uffs_os.h"
-#include "uffs/uffs_public.h"
-#include "uffs/uffs_version.h"
-#include "uffs/uffs_badblock.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#define PFX "util: "
-
-#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
-static void _ForceFormatAndCheckBlock(uffs_Device *dev, int block)
-{
-	u8 *pageBuf;
-	int pageSize;
-	int i, j;
-	uffs_Buf *buf;
-	UBOOL bad = U_TRUE;
-	int ret;
-
-	buf = uffs_BufClone(dev, NULL);
-	if (buf == NULL) {
-		uffs_Perror(UFFS_ERR_SERIOUS, "Alloc page buffer fail ! Format stoped.");
-		goto ext;
-	}
-
-	pageSize = dev->com.pg_data_size;
-	pageBuf = buf->data;
-
-
-	//step 1: Erase, fully fill with 0x0, and check
-	ret = dev->ops->EraseBlock(dev, block);
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		goto bad_out;
-
-	memset(pageBuf, 0, pageSize);
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		ret = dev->ops->WritePageData(dev, block, i, pageBuf, pageSize, NULL);
-		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-			goto bad_out;
-		ret = dev->ops->WritePageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size, U_TRUE);
-		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-			goto bad_out;
-	}
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		memset(pageBuf, 0xFF, pageSize);
-		dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
-		for (j = 0; j < pageSize; j++) {
-			if(pageBuf[j] != 0)
-				goto bad_out;
-		}
-		memset(pageBuf, 0xFF, dev->attr->spare_size);
-		dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
-		for (j = 0; j < dev->attr->spare_size; j++) {
-			if(pageBuf[j] != 0)
-				goto bad_out;
-		}
-	}
-
-	//step 2: Erase, and check
-	ret = dev->ops->EraseBlock(dev, block);
-	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
-		goto bad_out;
-
-	for (i = 0; i < dev->attr->pages_per_block; i++) {
-		memset(pageBuf, 0, pageSize);
-		dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
-		for (j = 0; j < pageSize; j++) {
-			if(pageBuf[j] != 0xFF)
-				goto bad_out;
-		}
-		memset(pageBuf, 0, dev->attr->spare_size);
-		dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
-		for (j = 0; j < dev->attr->spare_size; j++) {
-			if(pageBuf[j] != 0xFF)
-				goto bad_out;
-		}
-	}
-
-	// format succ
-	bad = U_FALSE;
-
-bad_out:
-	if (bad == U_TRUE)
-		uffs_FlashMarkBadBlock(dev, block);
-ext:
-	if (buf) 
-		uffs_BufFreeClone(dev, buf);
-
-	return;
-}
-#endif
-
-
-
-URET uffs_FormatDevice(uffs_Device *dev)
-{
-	u16 i, slot;
-	
-	if (dev == NULL)
-		return U_FAIL;
-
-	if (dev->ops == NULL) 
-		return U_FAIL;
-
-
-	if (uffs_BufIsAllFree(dev) == U_FALSE) {
-		uffs_Perror(UFFS_ERR_NORMAL, "some page still in used!");
-		return U_FAIL;
-	}
-
-	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
-		if (dev->buf.dirtyGroup[slot].count > 0) {
-			uffs_Perror(UFFS_ERR_SERIOUS, "there still have dirty pages!");
-			return U_FAIL;
-		}
-	}
-
-	uffs_BufSetAllEmpty(dev);
-
-
-	if (uffs_BlockInfoIsAllFree(dev) == U_FALSE) {
-		uffs_Perror(UFFS_ERR_NORMAL, "there still have block info cache ? fail to format");
-		return U_FAIL;
-	}
-
-	uffs_BlockInfoExpireAll(dev);
-
-	for (i = dev->par.start; i <= dev->par.end; i++) {
-		if (uffs_FlashIsBadBlock(dev, i) == U_FALSE) {
-			uffs_FlashEraseBlock(dev, i);
-			if (HAVE_BADBLOCK(dev))
-				uffs_BadBlockProcess(dev, NULL);
-		}
-		else {
-#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
-			_ForceFormatAndCheckBlock(dev, i);
-#endif
-		}
-	}
-
-	if (uffs_TreeRelease(dev) == U_FAIL) {
-		return U_FAIL;
-	}
-
-	if (uffs_TreeInit(dev) == U_FAIL) {
-		return U_FAIL;
-	}
-
-	if (uffs_BuildTree(dev) == U_FAIL) {
-		return U_FAIL;
-	}
-	
-	return U_SUCC;
-}
-
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_utils.c
+ * \brief utilities of uffs
+ * \author Ricky Zheng, created 12th May, 2005
+ */
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_utils.h"
+#include "uffs/uffs_os.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_version.h"
+#include "uffs/uffs_badblock.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define PFX "util: "
+
+#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
+static void _ForceFormatAndCheckBlock(uffs_Device *dev, int block)
+{
+	u8 *pageBuf;
+	int pageSize;
+	int i, j;
+	uffs_Buf *buf;
+	UBOOL bad = U_TRUE;
+	int ret;
+
+	buf = uffs_BufClone(dev, NULL);
+	if (buf == NULL) {
+		uffs_Perror(UFFS_ERR_SERIOUS, "Alloc page buffer fail ! Format stoped.");
+		goto ext;
+	}
+
+	pageSize = dev->com.pg_data_size;
+	pageBuf = buf->data;
+
+
+	//step 1: Erase, fully fill with 0x0, and check
+	ret = dev->ops->EraseBlock(dev, block);
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		goto bad_out;
+
+	memset(pageBuf, 0, pageSize);
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		ret = dev->ops->WritePageData(dev, block, i, pageBuf, pageSize, NULL);
+		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+			goto bad_out;
+		ret = dev->ops->WritePageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size, U_TRUE);
+		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+			goto bad_out;
+	}
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		memset(pageBuf, 0xFF, pageSize);
+		dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
+		for (j = 0; j < pageSize; j++) {
+			if(pageBuf[j] != 0)
+				goto bad_out;
+		}
+		memset(pageBuf, 0xFF, dev->attr->spare_size);
+		dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
+		for (j = 0; j < dev->attr->spare_size; j++) {
+			if(pageBuf[j] != 0)
+				goto bad_out;
+		}
+	}
+
+	//step 2: Erase, and check
+	ret = dev->ops->EraseBlock(dev, block);
+	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
+		goto bad_out;
+
+	for (i = 0; i < dev->attr->pages_per_block; i++) {
+		memset(pageBuf, 0, pageSize);
+		dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
+		for (j = 0; j < pageSize; j++) {
+			if(pageBuf[j] != 0xFF)
+				goto bad_out;
+		}
+		memset(pageBuf, 0, dev->attr->spare_size);
+		dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
+		for (j = 0; j < dev->attr->spare_size; j++) {
+			if(pageBuf[j] != 0xFF)
+				goto bad_out;
+		}
+	}
+
+	// format succ
+	bad = U_FALSE;
+
+bad_out:
+	if (bad == U_TRUE)
+		uffs_FlashMarkBadBlock(dev, block);
+ext:
+	if (buf) 
+		uffs_BufFreeClone(dev, buf);
+
+	return;
+}
+#endif
+
+
+
+URET uffs_FormatDevice(uffs_Device *dev)
+{
+	u16 i, slot;
+	
+	if (dev == NULL)
+		return U_FAIL;
+
+	if (dev->ops == NULL) 
+		return U_FAIL;
+
+
+	if (uffs_BufIsAllFree(dev) == U_FALSE) {
+		uffs_Perror(UFFS_ERR_NORMAL, "some page still in used!");
+		return U_FAIL;
+	}
+
+	for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
+		if (dev->buf.dirtyGroup[slot].count > 0) {
+			uffs_Perror(UFFS_ERR_SERIOUS, "there still have dirty pages!");
+			return U_FAIL;
+		}
+	}
+
+	uffs_BufSetAllEmpty(dev);
+
+
+	if (uffs_BlockInfoIsAllFree(dev) == U_FALSE) {
+		uffs_Perror(UFFS_ERR_NORMAL, "there still have block info cache ? fail to format");
+		return U_FAIL;
+	}
+
+	uffs_BlockInfoExpireAll(dev);
+
+	for (i = dev->par.start; i <= dev->par.end; i++) {
+		if (uffs_FlashIsBadBlock(dev, i) == U_FALSE) {
+			uffs_FlashEraseBlock(dev, i);
+			if (HAVE_BADBLOCK(dev))
+				uffs_BadBlockProcess(dev, NULL);
+		}
+		else {
+#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
+			_ForceFormatAndCheckBlock(dev, i);
+#endif
+		}
+	}
+
+	if (uffs_TreeRelease(dev) == U_FAIL) {
+		return U_FAIL;
+	}
+
+	if (uffs_TreeInit(dev) == U_FAIL) {
+		return U_FAIL;
+	}
+
+	if (uffs_BuildTree(dev) == U_FAIL) {
+		return U_FAIL;
+	}
+	
+	return U_SUCC;
+}
+

+ 67 - 67
components/dfs/filesystems/uffs/src/uffs/uffs_version.c

@@ -1,67 +1,67 @@
-/*
-  This file is part of UFFS, the Ultra-low-cost Flash File System.
-  
-  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
-
-  UFFS is free software; you can redistribute it and/or modify it under
-  the GNU Library General Public License as published by the Free Software 
-  Foundation; either version 2 of the License, or (at your option) any
-  later version.
-
-  UFFS is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  or GNU Library General Public License, as applicable, for more details.
- 
-  You should have received a copy of the GNU General Public License
-  and GNU Library General Public License along with UFFS; if not, write
-  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA  02110-1301, USA.
-
-  As a special exception, if other files instantiate templates or use
-  macros or inline functions from this file, or you compile this file
-  and link it with other works to produce a work based on this file,
-  this file does not by itself cause the resulting work to be covered
-  by the GNU General Public License. However the source code for this
-  file must still be made available in accordance with section (3) of
-  the GNU General Public License v2.
- 
-  This exception does not invalidate any other reasons why a work based
-  on this file might be covered by the GNU General Public License.
-*/
-
-/**
- * \file uffs_version.c
- * \brief uffs version information
- * \author Ricky Zheng, created 8th May, 2005
- */
-
-#include "uffs/uffs_version.h"
-#include "uffs/uffs_config.h"
-
-#include <stdio.h>
-#define PFX "ver: "
-
-
-static char version_buf[8];
-
-const char * uffs_Version2Str(int ver)
-{
-	sprintf(version_buf, "%1d.%02d.%04d", (ver&0xff000000) >> 24, (ver&0xff0000) >> 16, (ver&0xffff));
-	return version_buf;
-}
-
-int uffs_GetVersion(void)
-{
-	return UFFS_VERSION;
-}
-
-int uffs_GetMainVersion(int ver)
-{
-	return (ver&0xff000000) >> 24;
-}
-
-int uffs_GetMinorVersion(int ver)
-{
-	return (ver&0xff0000) >> 16;
-}
+/*
+  This file is part of UFFS, the Ultra-low-cost Flash File System.
+  
+  Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
+
+  UFFS is free software; you can redistribute it and/or modify it under
+  the GNU Library General Public License as published by the Free Software 
+  Foundation; either version 2 of the License, or (at your option) any
+  later version.
+
+  UFFS is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  or GNU Library General Public License, as applicable, for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  and GNU Library General Public License along with UFFS; if not, write
+  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA  02110-1301, USA.
+
+  As a special exception, if other files instantiate templates or use
+  macros or inline functions from this file, or you compile this file
+  and link it with other works to produce a work based on this file,
+  this file does not by itself cause the resulting work to be covered
+  by the GNU General Public License. However the source code for this
+  file must still be made available in accordance with section (3) of
+  the GNU General Public License v2.
+ 
+  This exception does not invalidate any other reasons why a work based
+  on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_version.c
+ * \brief uffs version information
+ * \author Ricky Zheng, created 8th May, 2005
+ */
+
+#include "uffs/uffs_version.h"
+#include "uffs/uffs_config.h"
+
+#include <stdio.h>
+#define PFX "ver: "
+
+
+static char version_buf[8];
+
+const char * uffs_Version2Str(int ver)
+{
+	sprintf(version_buf, "%1d.%02d.%04d", (ver&0xff000000) >> 24, (ver&0xff0000) >> 16, (ver&0xffff));
+	return version_buf;
+}
+
+int uffs_GetVersion(void)
+{
+	return UFFS_VERSION;
+}
+
+int uffs_GetMainVersion(int ver)
+{
+	return (ver&0xff000000) >> 24;
+}
+
+int uffs_GetMinorVersion(int ver)
+{
+	return (ver&0xff0000) >> 16;
+}