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

📄 uffs_fs.c

📁 nandflash文件系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return U_SUCC;

err:
	if (obj->dev) {
		uffs_PutDevice(obj->dev);
		obj->dev = NULL;
	}

	return U_FAIL;
}

URET uffs_OpenObject(uffs_Object *obj, const char *fullname, int oflag, int pmode)
{
	URET ret = U_FAIL;

	if ((ret = _PrepareOpenObj(obj, fullname, oflag, pmode)) == U_SUCC) {
		if (obj->nameLen > 0) {
			uffs_ObjectDevLock(obj);
			ret = _OpenObjectUnder(obj);
			uffs_ObjectDevUnLock(obj);
		}
	}

	if(ret == U_FAIL)
		_ReleaseObjectResource(obj);

	return ret;
}

static void _ReleaseObjectResource(uffs_Object *obj)
{
	if (obj) {
		if (obj->dev) {
			if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
			if (obj->devLockCount > 0) {
				uffs_ObjectDevUnLock(obj);
			}
			uffs_PutDevice(obj->dev);
			obj->dev = NULL;
		}
	}
}

URET uffs_CloseObject(uffs_Object *obj)
{
	uffs_Device *dev;
	uffs_Buf *buf;
	uffs_fileInfo fi;

	if(obj == NULL || obj->dev == NULL) return U_FAIL;
	if (obj->openSucc != U_TRUE) goto out;

	dev = obj->dev;
	uffs_ObjectDevLock(obj);

	if(obj->oflag & (UO_WRONLY|UO_RDWR|UO_APPEND|UO_CREATE|UO_TRUNC)) {

#ifdef 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, PFX"can't get file header\n");
				uffs_BufFlush(dev);
				uffs_ObjectDevUnLock(obj);
				goto out;
			}
			uffs_BufRead(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
			fi.lastModify = uffs_GetCurDateTime();
			uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
			uffs_BufPut(dev, buf);
		}
#endif

		uffs_BufFlush(dev);
	}
	uffs_ObjectDevUnLock(obj);

out:
	_ReleaseObjectResource(obj);

	return U_SUCC;
}

static u16 _GetFdnByOfs(uffs_Object *obj, u32 ofs)
{
	uffs_Device *dev = obj->dev;
	if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
		return 0;
	}
	else {
		ofs -= obj->pagesOnHead * dev->com.pgDataSize;
		return (ofs / (dev->com.pgDataSize * dev->attr->pages_per_block)) + 1;
	}
}

//static u16 _GetPageIdByOfs(uffs_Object *obj, u32 ofs)
//{
//	uffs_Device *dev = obj->dev;
//	if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
//		return (ofs / dev->com.pgDataSize) + 1; //in file header, pageID start from 1, not 0
//	}
//	else {
//		ofs -= (obj->pagesOnHead * dev->com.pgDataSize);
//		ofs %= (dev->com.pgDataSize * dev->attr->pages_per_block);
//		return ofs / dev->com.pgDataSize;
//	}
//}
//
//static UBOOL _IsAtTheStartOfBlock(uffs_Object *obj, u32 ofs)
//{
//	uffs_Device *dev = obj->dev;
//	int n;
//
//	if((ofs % dev->com.pgDataSize) != 0) return U_FALSE;
//	if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
//		return U_FALSE;
//	}
//	else {
//		n = ofs - (obj->pagesOnHead * dev->com.pgDataSize);
//		if(n % (dev->com.pgDataSize * dev->attr->pages_per_block) == 0) return U_TRUE;
//	}
//
//	return U_FALSE;
//}
//
static u32 _GetStartOfDataBlock(uffs_Object *obj, u16 fdn)
{
	if(fdn == 0) {
		return 0;
	}
	else {
		return (obj->pagesOnHead * obj->dev->com.pgDataSize) +
			(fdn - 1) * (obj->dev->com.pgDataSize * obj->dev->attr->pages_per_block);
	}
}


static int _WriteNewBlock(uffs_Object *obj,
						  const void *data, u32 len,
						  u16 father,
						  u16 serial)
{
	uffs_Device *dev = obj->dev;
	u16 pageID;
	int wroteSize = 0;
	int size;
	uffs_Buf *buf;
	URET ret;

	for(pageID = 0; pageID < dev->attr->pages_per_block; pageID++) {
		size = (len - wroteSize) > dev->com.pgDataSize ?
			dev->com.pgDataSize : len - wroteSize;
		if(size <= 0) break;

		buf = uffs_BufNew(dev, UFFS_TYPE_DATA, father, serial, pageID);
		if(buf == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't create a new page ?\n");
			break;
		}
		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, 0, size);
		uffs_BufPut(dev, buf);

		if(ret != U_SUCC) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"write data fail!\n");
			break;
		}
		wroteSize += size;
		obj->node->u.file.len += size;
	}
	return wroteSize;
}

static int _WriteInternalBlock(uffs_Object *obj,
							   TreeNode *node,
							   u16 fdn,
							   const void *data,
							   u32 len,
							   u32 blockOfs)
{
	uffs_Device *dev = obj->dev;
	u16 maxPageID;
	u16 pageID;
	u32 size;
	u32 pageOfs;
	u32 wroteSize = 0;
	URET ret;
	uffs_Buf *buf;
	u32 startOfBlock;
	u8 type;
	u16 father, serial;

	startOfBlock = _GetStartOfDataBlock(obj, fdn);
	if(fdn == 0) {
		type = UFFS_TYPE_FILE;
		father = node->u.file.father;
		serial = node->u.file.serial;
	}
	else {
		type = UFFS_TYPE_DATA;
		father = node->u.data.father;
		serial = fdn;
	}

	if(fdn == 0) maxPageID = obj->pagesOnHead;
	else maxPageID = dev->attr->pages_per_block - 1;


	while(wroteSize < len) {
		pageID = blockOfs / dev->com.pgDataSize;
		if(fdn == 0) pageID++; //in file header, pageID start from 1, not 0.
		if(pageID > maxPageID) break;

		pageOfs = blockOfs % dev->com.pgDataSize;
		size = (len - wroteSize + pageOfs) > dev->com.pgDataSize ?
			(dev->com.pgDataSize - pageOfs) : (len - wroteSize);

		if((obj->node->u.file.len % dev->com.pgDataSize) == 0 &&
			(blockOfs + startOfBlock) == obj->node->u.file.len) {

			buf = uffs_BufNew(dev, type, father, serial, pageID);
			if(buf == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can create a new buf!\n");
				break;
			}
		}
		else {
			buf = uffs_BufGetEx(dev, type, node, pageID);
			if(buf == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buffer ?\n");
				break;
			}
		}

		ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, pageOfs, size);
		uffs_BufPut(dev, buf);
		if(ret == U_FAIL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"write inter data fail!\n");
			break;
		}

		wroteSize += size;
		blockOfs += size;

		if(startOfBlock + blockOfs > obj->node->u.file.len)
			obj->node->u.file.len = startOfBlock + 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->openSucc == U_FALSE) return 0;

	if (obj->type == UFFS_TYPE_DIR) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't write to an dir object!\n");
		return 0;
	}

	if(obj->pos > fnode->u.file.len) return 0; //can't write file out of range

	if(obj->oflag == UO_RDONLY) 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, PFX"write point out of file ?\n");
			break;
		}

		fdn = _GetFdnByOfs(obj, write_start);

		if(write_start == fnode->u.file.len && fdn > 0 &&
			write_start == _GetStartOfDataBlock(obj, fdn)) {
			if(dev->tree.erasedCount < MINIMUN_ERASED_BLOCK) {
				uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient block in write obj, new block\n");
				break;
			}
			size = _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_BufFlush(dev);

			if(size == 0) break;
			remain -= size;
		}
		else {

			if(fdn == 0)
				dnode = obj->node;
			else
				dnode = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);

			if(dnode == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node in tree ?\n");
				break;
			}
			size = _WriteInternalBlock(obj, dnode, fdn,
									(u8 *)data + len - remain, remain,
									write_start - _GetStartOfDataBlock(obj, fdn));
#ifdef FLUSH_BUF_AFTER_WRITE
			uffs_BufFlush(dev);
#endif
			if(size == 0) break;
			remain -= size;
		}
	}

	obj->pos += (len - remain);

	if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(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 pageID;
	u8 type;
	u32 pageOfs;

	if (obj == NULL) return 0;
	if (obj->dev == NULL || obj->openSucc == U_FALSE) return 0;


	if (obj->type == UFFS_TYPE_DIR) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't read from a dir object!\n");
		return 0;
	}

	if(obj->pos > fnode->u.file.len) return 0; //can't read file out of range
	if(obj->oflag & UO_WRONLY) 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, PFX"read point out of file ?\n");
			break;
		}

		fdn = _GetFdnByOfs(obj, read_start);
		if(fdn == 0) {
			dnode = obj->node;
			type = UFFS_TYPE_FILE;
		}
		else {
			type = UFFS_TYPE_DATA;
			dnode = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
			if(dnode == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get data node in entry!\n");
				break;
			}
		}

		blockOfs = _GetStartOfDataBlock(obj, fdn);
		pageID = (read_start - blockOfs) / dev->com.pgDataSize;

		if(fdn == 0) {
			/**
			 * fdn == 0: this means that the reading range is start from the first block,
			 * since the page 0 is for file attr, so we move to the next page ID.
			 */
			pageID++;
		}

		buf = uffs_BufGetEx(dev, type, dnode, (u16)pageID);
		if(buf == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buffer when read obj.\n");
			break;
		}

		pageOfs = read_start % dev->com.pgDataSize;
		if(pageOfs >= buf->dataLen) {
			//uffs_Perror(UFFS_ERR_NOISY, PFX"read data out of page range ?\n");
			uffs_BufPut(dev, buf);
			break;
		}
		size = (remain + pageOfs > buf->dataLen ? buf->dataLen - 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_RecoverBadBlock(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, PFX"Can't seek a dir object!\n");
		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;
}

/**
 * return 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->openSucc == 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->openSucc == U_TRUE) {
			if (obj->pos >= obj->node->u.file.len) {
				return 1;
			}
			else {
				return 0;
			}
		}
	}

	return -1;
}

static URET _CoverOnePage(uffs_Device *dev,
						  uffs_Tags *old,
						  uffs_Tags *newTag,
						  u16 newBlock,
						  u16 page,
						  int newTimeStamp,
						  uffs_Buf *buf,
						  u32 length)
{
	newTag->father = buf->father;
	newTag->serial = buf->serial;
	newTag->type = buf->type;
	newTag->blockTimeStamp = newTimeStamp;
	newTag->dataLength = length;
	newTag->dataSum = old->dataSum;
	newTag->pageID = (u8)(buf->pageID);


	return uffs_WriteDataToNewPage(dev, newBlock, page, newTag, buf);
}

static URET _TruncateInternalWithBlockRecover(uffs_Object *obj, u16 fdn, u32 remain)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = obj->node;
	u16 pageID, maxPageID;
	TreeNode *node, *newNode = NULL;
	u16 block = UFFS_INVALID_BLOCK, newBlock = UFFS_INVALID_BLOCK;
	uffs_blockInfo *bc = NULL, *newBc = NULL;
	uffs_Buf *buf = NULL;
	uffs_Tags *tag, *newTag;
	URET ret = U_FAIL;
	u8 type = UFFS_TYPE_RESV;
	u32 startOfBlock;
	u32 end;
	int timeStamp;
	u16 page;

	if(fdn == 0) {
		node = fnode;
		block = node->u.file.block;
		type = UFFS_TYPE_FILE;
		maxPageID = obj->pagesOnHead;
	}
	else {
		node = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
		if(node == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node when truncate obj\n");
			goto _err;
		}
		block = node->u.data.block;
		type = UFFS_TYPE_DATA;
		maxPageID = dev->attr->pages_per_block - 1;
	}


	bc = uffs_GetBlockInfo(dev, block);
	if(bc == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when truncate obj\n");
		goto _err;
	}

	newNode = uffs_GetErased(dev);
	if(newNode == NULL) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient erased block, can't truncate obj.\n");
		goto _err;
	}
	newBlock = newNode->u.list.block;
	newBc = uffs_GetBlockInfo(dev, newBlock);
	if(newBc == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when truncate obj\n");
		goto _err;
	}

	startOfBlock = _GetStartOfDataBlock(obj, fdn);
	timeStamp = uffs_GetBlockTimeStamp(dev, bc);
	timeStamp = uffs_GetNextBlockTimeStamp(timeStamp);

	for(pageID = 0; pageID <= maxPageID; pageID++) {
		page = uffs_FindPageInBlockWithPageId(dev, bc, pageID);
		if(page == UFFS_INVALID_PAGE) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown error, truncate\n");
			break;
		}
		page = uffs_FindBestPageInBlock(dev, bc, page);
		buf = uffs_BufClone(dev, NULL);
		if(buf == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't clone page buffer\n");
			goto _err;

⌨️ 快捷键说明

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