diff options
| author | [email protected] <[email protected]> | 2011-01-16 13:30:54 +0000 |
|---|---|---|
| committer | [email protected] <[email protected]> | 2011-01-16 13:30:54 +0000 |
| commit | 0030a2d396187a9fb9e665fa2f535eeeedd601a5 (patch) | |
| tree | ebf490f8ea93620a60217ed14d9f8c7d52d2afa1 /components | |
| parent | dede5414decc94bcdf8730c44a855be042fadbde (diff) | |
add support uffs interface
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1243 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'components')
47 files changed, 12409 insertions, 12882 deletions
diff --git a/components/dfs/filesystems/uffs/dfs_uffs.c b/components/dfs/filesystems/uffs/dfs_uffs.c index 43ce7d4496..ad88f36419 100644 --- a/components/dfs/filesystems/uffs/dfs_uffs.c +++ b/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);
-static int dfs_uffs_lseek(struct dfs_fd* fd, rt_off_t offset)
+ /* update position */
+ fd->pos = fp->pos;
+
+ 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;
+ }
-static int dfs_uffs_getdents(struct dfs_fd* fd, struct _dirent* dirp, rt_uint32_t count)
+ fp = (uffs_Object*)(fd->data);
+ RT_ASSERT(fp != RT_NULL);
+
+ 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;
+
+ fp = (uffs_Object*)(fd->data);
+ RT_ASSERT(fp != RT_NULL);
+
+ return uffs_FlushObject(fp);
+}
-static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* pathname)
+int dfs_uffs_lseek(struct dfs_fd* fd, rt_off_t offset)
{
-}
+ uffs_Object* fp;
-static int dfs_uffs_stat(struct dfs_filesystem* fs, const char* filename, struct _stat* buf)
+ fp = (uffs_Object*)(fd->data);
+ RT_ASSERT(fp != RT_NULL);
+
+ 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;
+
-static int dfs_uffs_rename(struct dfs_filesystem* fs, const char* oldpath, const char* newpath)
+ d->d_type = DFS_DT_DIR;
+
+ 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);
-static const struct dfs_filesystem_operation _uffs =
+ return ret;
+}
+
+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,
+ 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;
- 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,
-};
+ return U_SUCC;
+ }
-int dfs_uffs_init(void)
+ 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);
+}
+
diff --git a/components/dfs/filesystems/uffs/dfs_uffs.h b/components/dfs/filesystems/uffs/dfs_uffs.h index 0f6d497c7c..b835f7b00f 100644 --- a/components/dfs/filesystems/uffs/dfs_uffs.h +++ b/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
+
diff --git a/components/dfs/filesystems/uffs/src/emu/cmdline.h b/components/dfs/filesystems/uffs/src/emu/cmdline.h index b71a10f5ab..38c11e577c 100644 --- a/components/dfs/filesystems/uffs/src/emu/cmdline.h +++ b/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 diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_os_posix.c b/components/dfs/filesystems/uffs/src/emu/uffs_os_posix.c index 780cc91dfc..b026adce3d 100644 --- a/components/dfs/filesystems/uffs/src/emu/uffs_os_posix.c +++ b/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; } diff --git a/components/dfs/filesystems/uffs/src/example/CMakeLists.txt b/components/dfs/filesystems/uffs/src/example/CMakeLists.txt index 24e9aecfba..e60bf636d0 100644 --- a/components/dfs/filesystems/uffs/src/example/CMakeLists.txt +++ b/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)
diff --git a/components/dfs/filesystems/uffs/src/example/flash-interface-example.c b/components/dfs/filesystems/uffs/src/example/flash-interface-example.c index b7427e2921..7130f6fc5a 100644 --- a/components/dfs/filesystems/uffs/src/example/flash-interface-example.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
+
+/////////////////////////////////////////////////////////////////////////////////
diff --git a/components/dfs/filesystems/uffs/src/example/static-mem-allocate.c b/components/dfs/filesystems/uffs/src/example/static-mem-allocate.c index c0f7d510ea..45e293fcc7 100644 --- a/components/dfs/filesystems/uffs/src/example/static-mem-allocate.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs.h index f2ef895e09..9a1f8f37f5 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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 - -#define UO_RDONLY 0x0000 /** read only */ -#define UO_WRONLY 0x0001 /** write only */ -#define UO_RDWR 0x0002 /** read and write */ -#define UO_APPEND 0x0008 /** append */ +#endif
-#define UO_BINARY 0x0000 /** no used in uffs */ +#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_CREATE 0x0100 -#define UO_TRUNC 0x0200 -#define UO_EXCL 0x0400 +#define UO_CREATE DFS_O_CREAT +#define UO_TRUNC DFS_O_TRUNC
+#define UO_EXCL DFS_O_EXCL
-#define UO_DIR 0x1000 /** open a directory */ +#define UO_DIR DFS_O_DIRECTORY /** 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 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 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* ���ļ��Ľ�βѰ�� */
-#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
+
-/** - * \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; - +/* + * \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 } diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_badblock.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_badblock.h index c6a5c0b104..3c785de3ad 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_badblock.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_blockinfo.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_blockinfo.h index fad75d4c2a..8494a8787a 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_blockinfo.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_buf.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_buf.h index c75ca57f29..7be6445c1f 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_buf.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_config.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_config.h index 59ba4cd478..2268266d3e 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_config.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_core.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_core.h index 1f18007f0f..997ab1f2f8 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_core.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_device.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_device.h index 52a5f559a8..b26f02396c 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_device.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_ecc.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_ecc.h index 425bc4ab63..481fc83729 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_ecc.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fd.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fd.h index 23e2532649..4de2958f83 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fd.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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);
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_find.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_find.h index 020d2c9455..ba78d91dd1 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_find.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_flash.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_flash.h index 7740bbd6bc..6f1d55d5d0 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_flash.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fs.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fs.h index 157105a520..76543ac42b 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fs.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mem.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mem.h index 9d2e2ee3fc..5f31885fbb 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mem.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mtb.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mtb.h index 3309e9d9bf..dd36c1a26f 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_mtb.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_os.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_os.h index 0b63f83755..d3a3b62694 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_os.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_pool.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_pool.h index 5fadd5485f..9df07c33ec 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_pool.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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_
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_public.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_public.h index 5b22c3b214..3e08e02428 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_public.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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_
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_tree.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_tree.h index ff36f2b33a..2c96d33f1f 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_tree.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_types.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_types.h index 0b614192bb..e5c2b57f70 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_types.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_utils.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_utils.h index b3de0a077b..2a6300396a 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_utils.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_version.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_version.h index 0330decf08..db6d356f00 100644 --- a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_version.h +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/CMakeLists.txt b/components/dfs/filesystems/uffs/src/uffs/CMakeLists.txt index 38f85fbfa3..79a0ff269a 100644 --- a/components/dfs/filesystems/uffs/src/uffs/CMakeLists.txt +++ b/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} )
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_badblock.c b/components/dfs/filesystems/uffs/src/uffs/uffs_badblock.c index 32dbb039d4..808c15a69f 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_badblock.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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, ®ion); - 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, ®ion);
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_blockinfo.c b/components/dfs/filesystems/uffs/src/uffs/uffs_blockinfo.c index 120a04df47..05e9c24777 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_blockinfo.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_buf.c b/components/dfs/filesystems/uffs/src/uffs/uffs_buf.c index fc1adf72b4..667178dfe1 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_buf.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
+
+
+
+
+
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_debug.c b/components/dfs/filesystems/uffs/src/uffs/uffs_debug.c index 13b46667d1..1c3cce4e58 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_debug.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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);
+}
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_device.c b/components/dfs/filesystems/uffs/src/uffs/uffs_device.c index fb52f4892a..3460f1c6ab 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_device.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_ecc.c b/components/dfs/filesystems/uffs/src/uffs/uffs_ecc.c index 3ad4e212f4..c9aa5a6640 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_ecc.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_fd.c b/components/dfs/filesystems/uffs/src/uffs/uffs_fd.c index cad91346ff..7d6261873f 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_fd.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_find.c b/components/dfs/filesystems/uffs/src/uffs/uffs_find.c index 6c525620de..4226672c99 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_find.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_flash.c b/components/dfs/filesystems/uffs/src/uffs/uffs_flash.c index e59eaa6052..bd8476d535 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_flash.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_fs.c b/components/dfs/filesystems/uffs/src/uffs/uffs_fs.c index 2363d3ba73..dbd8ed6c77 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_fs.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_init.c b/components/dfs/filesystems/uffs/src/uffs/uffs_init.c index 2eb56c458e..1cf96fd5c0 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_init.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_mem.c b/components/dfs/filesystems/uffs/src/uffs/uffs_mem.c index 27ca45c9fb..9309a0f17d 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_mem.c +++ b/components/dfs/filesystems/uffs/src/uffs/uffs_mem.c @@ -3,29 +3,6 @@ Copyright (C) 2005-2009 Ricky Zheng <[email protected]> - 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 - - - diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c b/components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c index f669dea94f..c09d82a649 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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--;
+}
+
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_pool.c b/components/dfs/filesystems/uffs/src/uffs/uffs_pool.c index 0e05856ed8..a6c3615b70 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_pool.c +++ b/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 <[email protected]> - - 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; -}
\ No newline at end of file +/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
+
+ 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;
+}
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_public.c b/components/dfs/filesystems/uffs/src/uffs/uffs_public.c index b5a2cdfc97..df02d2c2f6 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_public.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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
+
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_tree.c b/components/dfs/filesystems/uffs/src/uffs/uffs_tree.c index fded8f0097..02c6b27db3 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_tree.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+ }
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_utils.c b/components/dfs/filesystems/uffs/src/uffs/uffs_utils.c index e65ceb049d..2ea31ae0a1 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_utils.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
+
diff --git a/components/dfs/filesystems/uffs/src/uffs/uffs_version.c b/components/dfs/filesystems/uffs/src/uffs/uffs_version.c index 9e257ce2dd..7eb16f017c 100644 --- a/components/dfs/filesystems/uffs/src/uffs/uffs_version.c +++ b/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 <[email protected]> - - 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 <[email protected]>
+
+ 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;
+}
|
