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

📄 uffs_fs.c

📁 nandflash文件系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
    Copyright (C) 2005-2008  Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>

    This library is free software; you can redistribute it and/or
    modify it under the terms of 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.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/
/**
 * \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/ubuffer.h"
#include "uffs/uffs_ecc.h"
#include "uffs/uffs_badblock.h"
#include "uffs/uffs_os.h"
#include <string.h> 
#include <stdio.h>

#define PFX "fs:"

#define GET_SERIAL_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.serial : (obj)->node->u.file.serial)
#define GET_BLOCK_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.block : (obj)->node->u.file.block)

static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode);
static URET _CreateObjectUnder(uffs_Object *obj);
static void _ReleaseObjectResource(uffs_Object *obj);
static URET _TruncateObject(uffs_Object *obj, u32 remain);

static int _object_buf[sizeof(uffs_Object) * MAX_OBJECT_HANDLE / sizeof(int)];
static struct ubufm _object_dis = {
	_object_buf,
	sizeof(uffs_Object),
	MAX_OBJECT_HANDLE,
	NULL,
	0,
};


/**
 * initialise object buffers, called by UFFS internal
 */
URET uffs_InitObjectBuf(void)
{
	if(uBufInit(&_object_dis) < 0) return U_FAIL;
	else return U_SUCC;
}

/**
 * Release object buffers, called by UFFS internal
 */
URET uffs_ReleaseObjectBuf(void)
{
	return uBufRelease(&_object_dis) < 0 ? U_FAIL : U_SUCC;
}

/**
 * alloc a new object structure
 * \return the new object
 */
uffs_Object * uffs_GetObject(void)
{
	uffs_Object * obj;
	obj = (uffs_Object *)uBufGet(&_object_dis);
	if (obj) {
		memset(obj, 0, sizeof(uffs_Object));
		obj->openSucc = U_FALSE;
	}
	return obj;
}

/**
 * put the object struct back to system
 */
void uffs_PutObject(uffs_Object *obj)
{
	if(obj) uBufPut(obj, &_object_dis);
}

/**
 * \return the internal index num of object
 */
int uffs_GetObjectIndex(uffs_Object *obj)
{
	return uBufGetIndex(obj, &_object_dis);
}

/**
 * \return the object by the internal index
 */
uffs_Object * uffs_GetObjectByIndex(int idx)
{
	return (uffs_Object *) uBufGetBufByIndex(idx, &_object_dis);
}

static void uffs_ObjectDevLock(uffs_Object *obj)
{
	if (obj) {
		if (obj->dev) {
			uffs_DeviceLock(obj->dev);
			obj->devLockCount++;
		}
	}
}

static void uffs_ObjectDevUnLock(uffs_Object *obj)
{
	if (obj) {
		if (obj->dev) {
			obj->devLockCount--;
			uffs_DeviceUnLock(obj->dev);
		}
	}
} 

/** get path from fullname, return path length
 * fullname: "/abc/def"		|	"/abc/def/"		| "/"
 * ==> path: "/abc/"        |   "/abc/def/"		| "/"
 */
static int _getpath(const char *fullname, char *path)
{
	int i;
	int len;

	if (fullname[0] == 0) return 0;

	len = strlen(fullname);
	for (i = len - 1; i > 0 && fullname[i] != '/'; i--);

	i++;
	if (path) {
		memcpy(path, fullname, i);
		path[i] = 0;
	}

	return i;
}

/** get name from fullname
 * fullname: "/abc/def"		|	"/abc/def/"		| "/"
 *  returen: "def"          |   ""		        | ""
 */
static const char * _getname(const char *fullname)
{
	int pos = _getpath(fullname, NULL);

	return fullname + pos;
}

static int forwad_search_slash(const char *str, int pos)
{
	int len = strlen(str);
	while(str[pos] != '/' && pos < len) pos++;
	if (pos == len) 
		return -1;
	else
		return pos;
}

static int back_search_slash(const char *str, int pos)
{
	while (str[pos] != '/' && pos >= 0) pos--;
	return pos;
}

/**
 * create a new object and open it if success
 */
URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag, int pmode)
{
	URET ret = U_FAIL;

	oflag |= UO_CREATE;

	if (_PrepareOpenObj(obj, fullname, oflag, pmode) == U_SUCC) {
		uffs_ObjectDevLock(obj);
		ret  = _CreateObjectUnder(obj);
		uffs_ObjectDevUnLock(obj);
	}

	return ret;
}


/** find the matched mount point from path */
static int find_maxMatchedMountPoint(const char *path)
{
	char buf[MAX_PATH_LENGTH+1] = {0};
	int pos;
	uffs_Device *dev;

	pos = strlen(path);
	memcpy(buf, path, pos + 1);

	while(pos > 0) {
		if ((dev = uffs_GetDevice(buf)) != NULL ) {
			uffs_PutDevice(dev);
			return pos;
		}
		else {
			buf[pos - 1] = '\0'; //replace the last '/' with '\0'

			//back forward search the next '/'
			for (; pos > 0 && buf[pos-1] != '/'; pos--)
				buf[pos-1] = '\0';
		}
	}

	return pos;
}

static URET _CreateObjectUnder(uffs_Object *obj)
{
	/**
	 * \note: level 0 has been set in obj.
	 */
	uffs_Buf *buf = NULL;
	uffs_fileInfo fi, *pfi;
	URET ret;

	TreeNode *node;

	if (obj->type == UFFS_TYPE_DIR) {
		//find out whether have file with the same name
		node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
		if (node != NULL) {
			obj->err = UEEXIST;
			return U_FAIL;
		}
		obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
	}
	else {
		//find out whether have dir with the same name
		node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
		if (node != NULL) {
			obj->err = UEEXIST;
			return U_FAIL;
		}
		obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
	}

	if (obj->node) {
		/* dir|file already exist, truncate it to zero length */
		obj->serial = GET_SERIAL_FROM_NODE(obj);

		buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);

		if(buf == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"found in tree, but can' load buffer ?\n");
			goto err;
		}

		pfi = (uffs_fileInfo *)(buf->data);
		obj->access = pfi->access;
		obj->attr = pfi->attr;
		obj->createTime = pfi->createTime;
		obj->lastModify = pfi->lastModify;
		uffs_BufPut(obj->dev, buf);

		obj->pos = 0;

		obj->openSucc = U_TRUE;
		ret = _TruncateObject(obj, 0);
		if (ret != U_SUCC) {
			obj->openSucc = U_FALSE;
		}
		return ret;
	}

	/* 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, PFX"No free serial num!\n");
		goto err;
	}

	if(obj->dev->tree.erasedCount < MINIMUN_ERASED_BLOCK) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient block in create obj\n");
		goto err;
	}

	buf = uffs_BufNew(obj->dev, obj->type, obj->father, obj->serial, 0);
	if(buf == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't new buffer when create obj!\n");
		goto err;
	}

	memset(&fi, 0, sizeof(uffs_fileInfo));
	memcpy(fi.name, obj->name, obj->nameLen);
	fi.name[obj->nameLen] = '\0';
	fi.name_len = obj->nameLen;
	fi.access = 0;
	fi.attr |= FILE_ATTR_WRITE;
	if (obj->type == UFFS_TYPE_DIR)
		fi.attr |= FILE_ATTR_DIR;
	fi.createTime = fi.lastModify = uffs_GetCurDateTime();

	obj->createTime = fi.createTime;
	obj->lastModify = fi.lastModify;
	obj->attr = fi.attr;
	obj->access = fi.access;

	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_BufFlush(obj->dev);

	//update obj->node: after buf flushed, the NEW node can be found in the tree
	if (obj->type == UFFS_TYPE_DIR)
		obj->node = uffs_FindDirNodeFromTree(obj->dev, obj->serial);
	else
		obj->node = uffs_FindFileNodeFromTree(obj->dev, obj->serial);

	if(obj->node == NULL) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find the node in the tree ?\n");
		goto err;
	}

	if (obj->type == UFFS_TYPE_DIR) {
		//do nothing for dir ...
	}
	else {
		obj->node->u.file.len = 0;	//init the length to 0
	}

	if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
	obj->openSucc = U_TRUE;

	return U_SUCC;

err:
	if (buf && obj->dev) {
		uffs_BufPut(obj->dev, buf);
		buf = NULL;
	}

	return U_FAIL;
}


static URET _OpenObjectUnder(uffs_Object *obj)
{
	uffs_Buf *buf = NULL;
	uffs_fileInfo *fi = NULL;


	/*************** init level 1 ***************/
	if (obj->type == UFFS_TYPE_DIR) {
		obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
	}
	else {
		obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
	}

	if(obj->node == NULL) {
		/* dir|file not exist */
		if(obj->oflag & UO_CREATE){
			//create dir|file
			return _CreateObjectUnder(obj);
		}
		else {
			obj->err = UENOENT;
			//uffs_Perror(UFFS_ERR_NOISY, PFX"dir or file not found\n");
			return U_FAIL;
		}
	}

	obj->serial = GET_SERIAL_FROM_NODE(obj);

	buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);

	if(buf == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buf when open!\n");
		return U_FAIL;
	}

	fi = (uffs_fileInfo *)(buf->data);
	obj->attr = fi->attr;
	obj->createTime = fi->createTime;
	obj->lastModify = fi->lastModify;
	obj->access = fi->access;
	uffs_BufPut(obj->dev, buf);

	if((obj->oflag & (UO_CREATE | UO_EXCL)) == (UO_CREATE | UO_EXCL)){
		obj->err = UEEXIST;
		return U_FAIL;
	}

	obj->openSucc = U_TRUE;
	
	if(obj->oflag & UO_TRUNC) {
		if(_TruncateObject(obj, 0) == U_FAIL){
			//obj->err will be set in _TruncateObject
			return U_FAIL;
		}
	}

	obj->err = UENOERR;


	return U_SUCC;
}

/**
 * \brief search '/' in path from *pos
 * \param path the string to be search
 * \param pos[in/out] search start position, *pos will be updated after search
 * \return matched length
 */
static int getPathPart(const char *path, int *pos)
{
	int len = 0;

	for (len = 0; path[len+(*pos)] != '\0' && path[len+(*pos)] != '/'; len++) ;

	*pos += len;

	return len;
}

/** get dir's serial No. 
 *  path is the relative path from mount point: "abc/def/"  |  "" (in this case, return father)
 */
static u16 _GetDirSerial(uffs_Device *dev, const char *path, u16 father)
{
	int pos = 0;
	int pos_last = 0;
	int len = 0;
	char part[MAX_FILENAME_LENGTH+1] = {0};
	TreeNode * node;
	u16 sum;
	u16 serial = father;

	while((len = getPathPart(path, &pos)) > 0) {
		memcpy(part, path + pos_last, len);
		part[len] = '\0';
		sum = uffs_MakeSum16(part, len);
		node = uffs_FindDirNodeByName(dev, part, len, sum, serial);
		if (node) {
			serial = node->u.dir.serial;
			pos_last = ++pos;
		}
		else {
			return INVALID_UFFS_SERIAL;
		}
	}

	return serial;
}

/** prepare the object struct for open */
static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode)
{
	char buf[MAX_PATH_LENGTH+1] = {0};
	char mount[MAX_FILENAME_LENGTH+1] = {0};
	char *start_path = mount;
	int pos;
	int i, len;
	u8 type;

	type = (oflag & UO_DIR) ? UFFS_TYPE_DIR : UFFS_TYPE_FILE;

	obj->dev = NULL;

	if((oflag & (UO_WRONLY | UO_RDWR)) == (UO_WRONLY | UO_RDWR)){
		/* UO_WRONLY and UO_RDWR can't appear together */
		uffs_Perror(UFFS_ERR_NOISY, PFX"UO_WRONLY and UO_RDWR can't appear together\n");
		obj->err = UEINVAL;
		return U_FAIL;
	}

	obj->pos = 0;

	if (!fullname) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"bad file/dir name: %s\n", fullname);
		obj->err = UEINVAL;
		return U_FAIL;
	}

	/************** init level 0 **************/
	obj->oflag = oflag;
	obj->pmode = pmode;

	len = strlen(fullname);

	if (oflag & UO_DIR) {
		/** open a directory */
		obj->type = UFFS_TYPE_DIR;

		// dir name should end with '/'
		if (fullname[len-1] != '/') {
			uffs_Perror(UFFS_ERR_NOISY, PFX"bad dir name: %s\n", fullname);
			obj->err = UEINVAL;
			return U_FAIL;
		}
	}
	else {
		/** open a file */
		obj->type = UFFS_TYPE_FILE;

		if (fullname[len-1] == '/') {
			uffs_Perror(UFFS_ERR_NOISY, PFX"bad file name: %s\n", fullname);
			obj->err = UEINVAL;
			return U_FAIL;
		}
	}

	_getpath(fullname, buf);
	// get path from full name, now what's on buf:
	//	if it's dir:        "/abc/def/xyz/"  |  "/abc/"  |   "/abc/"  |  "/"
	//  if it's file:       "/abc/def/"      |  X        |   "/"      |  X


	pos = find_maxMatchedMountPoint(buf);
	if (pos == 0) {
		/* can't not find any mount point from the path ??? */
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find any mount point from the path %s\n", buf);
		obj->err = UENOENT;
		return U_FAIL;
	}

	// get mount point: "/abc/"	or "/"
	memcpy(mount, buf, pos);
	mount[pos] = '\0';

	obj->dev = uffs_GetDevice(mount);
	if (obj->dev == NULL) {
		// uffs_Perror(UFFS_ERR_NOISY, "Can't get device from mount point: %s\r\n", mount);
		obj->err = UENOENT;
		return U_FAIL;
	}

	//here is a good chance to deal with bad block ...
	if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);

	// get the rest name (fullname - mount point) to buf: 
	//   if the mount point is "/abc/", then:
	//		if it's dir:   "def/xyz/"     |   ""      |  ""     |  X
	//		if it's file:  "def/xyz"      |   X       |  X      |  X
	//   if the mount point is "/", then:
	//      if it's dir:   "abc/def/xyz/  |   "abc/"  |  "abc/" |  ""
	//      if it's file:  "abc/def/xyz"  |   X       |  "abc"  |  X
	len = strlen(fullname) - strlen(mount);
	memcpy(buf, fullname + strlen(mount), len);
	buf[len] = '\0';

	if (len == 0 && (oflag & UO_DIR) == 0) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"bad file name: %s\n", fullname);
		obj->err = UEINVAL;
		goto err;
	}

	if (oflag & UO_DIR) {
		if (len == 0) {

			// uffs_Perror(UFFS_ERR_NOISY, "Zero length name ? root dir ?\r\n");

			obj->father = PARENT_OF_ROOT;
			obj->serial = ROOT_DIR_ID;
			obj->nameLen = 0;
		}
		else {
			if (buf[len-1] == '/') {
				buf[len-1] = 0;
				len--;
			}
			for (i = len - 1; i >= 0 && buf[i] != '/'; i--);
			obj->nameLen = len - i - 1;
			strcpy(obj->name, buf + i + 1);
			if (i < 0) {
				obj->father = ROOT_DIR_ID;
			}
			else {
				buf[i+1] = 0;
				obj->father = _GetDirSerial(obj->dev, buf, ROOT_DIR_ID);
			}
		}
	}
	else {
		for(i = len - 1; i >= 0 && buf[i] != '/'; i--);
		obj->nameLen = len - i - 1;
		strcpy(obj->name, buf + i + 1);
		if (i < 0) {
			obj->father = ROOT_DIR_ID;
		}
		else {
			buf[i+1] = 0;
			obj->father = _GetDirSerial(obj->dev, buf, ROOT_DIR_ID);
		}
	}

	if (obj->father == INVALID_UFFS_SERIAL) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"can't open path %s\n", start_path);
		obj->err = UENOENT;
		goto err;
	}

	obj->sum = uffs_MakeSum16(obj->name, obj->nameLen);
	obj->encode = UFFS_DEFAULT_ENCODE;
	obj->pagesOnHead = obj->dev->attr->pages_per_block - 1;

	//uffs_Perror(UFFS_ERR_NOISY, "Prepare name: %s\r\n", obj->name);

⌨️ 快捷键说明

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