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

📄 uffs_fs.c

📁 nandflash文件系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		}
		tag = &(bc->spares[page].tag);
		uffs_LoadPhiDataToBuf(dev, buf, bc->blockNum, page);

		buf->father = tag->father;
		buf->serial = tag->serial;
		buf->type = tag->type;
		buf->pageID = tag->pageID;
		buf->dataLen = tag->dataLength;

		newTag = &(newBc->spares[pageID].tag);
		if(fdn == 0 && pageID == 0) {
			//copy the page file information
			ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
			if(ret != U_SUCC) break;
		}
		else {
			end = ((fdn == 0) ? (pageID - 1) * dev->com.pgDataSize :
					pageID * dev->com.pgDataSize);
			end += tag->dataLength;
			end += startOfBlock;

			if(remain > end) {
				if(tag->dataLength != dev->com.pgDataSize) {
					uffs_Perror(UFFS_ERR_NOISY, PFX" ???? unknown error when truncate. \n");
					break;
				}
				ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
				if(ret != U_SUCC) break;
			}
			else if(remain == end) {
				ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
				if(ret != U_SUCC) break;
			}
			else if(remain < end) {
				buf->dataLen = tag->dataLength - (end - remain);
				if(buf->dataLen == 0) {
					ret = U_SUCC;
					break;
				}
				memset(buf->data + buf->dataLen, 0, dev->com.pgDataSize - buf->dataLen);
				ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
				break;
			}
		}
		uffs_BufFreeClone(dev, buf);
		buf = NULL;
	}

_err:
	if(buf != NULL) {
		uffs_BufFreeClone(dev, buf);
		buf = NULL;
	}
	if(ret == U_SUCC) {
		//ok, modify the tree, and erase old block
		//NOTE: Don't delete the 'old' node from tree, just replace the 'block' with new block,
		//      so that we don't need to modify obj->node :)
		uffs_SetTreeNodeBlock(type, node, newNode->u.list.block);
		newNode->u.list.block = block;
		dev->ops->EraseBlock(dev, newNode->u.list.block);
		uffs_InsertToErasedListTail(dev, newNode);
	}
	else {
		//fail to cover block, so erase new block
		dev->ops->EraseBlock(dev, newBlock);
		uffs_InsertToErasedListTail(dev, newNode);
	}

	if(bc) uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
	if(bc) uffs_PutBlockInfo(dev, bc);
	if(newBc) uffs_ExpireBlockInfo(dev, newBc, UFFS_ALL_PAGES);
	if(newBc) uffs_PutBlockInfo(dev, newBc);

	return U_SUCC;
}

URET uffs_TruncateObject(uffs_Object *obj, u32 remain)
{
	URET ret;

	uffs_ObjectDevLock(obj);
	ret = _TruncateObject(obj, remain);
	uffs_ObjectDevUnLock(obj);

	return ret;
}

/** truncate obj without lock device */
static URET _TruncateObject(uffs_Object *obj, u32 remain)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = obj->node;
	u16 fdn;
	u32 flen;
	u32 startOfBlock;
	TreeNode *node;
	uffs_blockInfo *bc;
	uffs_Buf *buf;
	u16 page;

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

	/* do nothing if the obj is a dir */
	/* TODO: delete files under dir ? */
	if (obj->type == UFFS_TYPE_DIR) {
		obj->err = UEEXIST;
		return U_FAIL;
	}

	if(remain > fnode->u.file.len) return U_FAIL;

	uffs_BufFlush(dev); //flush dirty buffers first

	while(fnode->u.file.len > remain) {
		flen = fnode->u.file.len;
		fdn = _GetFdnByOfs(obj, flen - 1);

		startOfBlock = _GetStartOfDataBlock(obj, fdn);
		if(remain <= startOfBlock && fdn > 0) {
			node = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
			if(node == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node when trancate obj.\n");
				return U_FAIL;
			}
			bc = uffs_GetBlockInfo(dev, node->u.data.block);
			if(bc == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when trancate obj.\n");
				return U_FAIL;
			}
			for(page = 0; page < dev->attr->pages_per_block; page++) {
				buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page);
				if(buf) uffs_BufSetMark(buf, UFFS_BUF_EMPTY);
			}
			uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
			dev->ops->EraseBlock(dev, node->u.data.block);
			uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node);
			node->u.list.block = bc->blockNum;
			uffs_PutBlockInfo(dev, bc);
			uffs_InsertToErasedListTail(dev, node);
			fnode->u.file.len = startOfBlock;
		}
		else {
			if(_TruncateInternalWithBlockRecover(obj, fdn, remain) == U_SUCC) {
				fnode->u.file.len = remain;
			}
			else {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"fail to truncate obj\n");
				return U_FAIL;
			}
		}
	}

	if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);

	return U_SUCC;

}


/**
 * delete uffs object
 */
URET uffs_DeleteObject(const char * name)
{
	uffs_Object *obj;
	TreeNode *node;
	uffs_Device *dev;
	u16 block;
	uffs_Buf *buf;
	URET ret = U_FAIL;

	obj = uffs_GetObject();
	if (obj == NULL) goto err1;

	if (uffs_OpenObject(obj, name, UO_RDWR|UO_DIR, US_IREAD|US_IWRITE) == U_FAIL) {
		if (uffs_OpenObject(obj, name, UO_RDWR, US_IREAD|US_IWRITE) == U_FAIL)
			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_FindDirNodeFromTreeWithFather(dev, obj->serial);
		if (node != NULL) goto err;  //have sub dirs ?

		node = uffs_FindFileNodeFromTreeWithFather(dev, obj->serial);
		if (node != NULL) 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_BufFlush(dev);
	if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);

	buf = uffs_BufFind(dev, obj->father, obj->serial, 0);
	if (buf) {
		//need to expire this buffer ...
		if (buf->refCount != 0) {
			//there is other obj for this file still in use ?
			uffs_Perror(UFFS_ERR_NORMAL, PFX"Try to delete object but still have buf referenced.\n");
			goto err;
		}
		buf->mark = UFFS_BUF_EMPTY; //!< make this buffer expired.
	}
	//FIXME !!: need to take care of other obj->node ?
	uffs_BreakFromEntry(dev, obj->type, node);
	dev->ops->EraseBlock(dev, block); //!< ok, the object is deleted now.
	node->u.list.block = block;
	uffs_InsertToErasedListTail(dev, node);

	ret = U_SUCC;
err:
	uffs_ObjectDevUnLock(obj);
err1:
	_ReleaseObjectResource(obj);

	uffs_PutObject(obj);

	return ret;
}

URET uffs_RenameObject(const char *old_name, const char *new_name)
{
	uffs_Object *obj = NULL, *obj_new = NULL;
	uffs_Device *dev;
	TreeNode *node;
	uffs_Buf *buf;
	uffs_fileInfo fi;
	int pos, pos1, len, new_len, old_len;
	u16 father_new;
	URET ret = U_FAIL;

	obj = uffs_GetObject();
	obj_new = uffs_GetObject();

	if (!obj || !obj_new) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"Can't allocate uffs_Object.\n");
		return U_FAIL;
	}

	new_len = strlen(new_name);
	old_len = strlen(old_name);

	if(old_len >= MAX_PATH_LENGTH ||
		new_len >= MAX_PATH_LENGTH) return U_FAIL;

	if ((old_name[old_len-1] == '/' && new_name[new_len-1] != '/') ||
		(old_name[old_len-1] != '/' && new_name[new_len-1] == '/')) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't rename object between file and dir.\n");
		goto err_exit;
	}

	pos = find_maxMatchedMountPoint(old_name);
	pos1 = find_maxMatchedMountPoint(new_name);
	if (pos <= 0 || pos <= 0 || pos != pos1 || strncmp(old_name, new_name, pos) != 0) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't moving object to different mount point\n");
		goto err_exit;
	}

	/* check whether the new object exist ? */
	memset(obj, 0, sizeof(uffs_Object));
	if (new_name[new_len-1] == '/') {
		if (uffs_OpenObject(obj, new_name, UO_DIR|UO_RDONLY, US_IREAD) == U_SUCC) {
			uffs_CloseObject(obj);
			goto err_exit;
		}
	}
	else {
		if (uffs_OpenObject(obj, new_name, UO_RDONLY, US_IREAD) == U_SUCC) {
			uffs_CloseObject(obj);
			goto err_exit;
		}
	}

	/* check whether the old object exist ? */
	memset(obj, 0, sizeof(uffs_Object));
	if (old_name[old_len-1] == '/') {
		if (uffs_OpenObject(obj, old_name, UO_DIR|UO_RDONLY, US_IREAD) == U_FAIL) {
			goto err_exit;
		}
	}
	else {
		if (uffs_OpenObject(obj, old_name, UO_RDONLY, US_IREAD) == U_FAIL) {
			goto err_exit;
		}
	}

	/* get new object's farther's serail No. by prepare create the new object */
	memset(obj_new, 0, sizeof(uffs_Object));
	if (_PrepareOpenObj(obj_new, new_name, UO_RDWR, US_IREAD|US_IWRITE) == U_FAIL) {
		goto err_exit;
	}
	father_new = obj_new->father;
	_ReleaseObjectResource(obj_new);

	dev = obj->dev;
	node = obj->node;

	uffs_ObjectDevLock(obj);

	uffs_BufFlush(dev);

	buf = uffs_BufGetEx(dev, obj->type, node, 0);
	if(buf == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buf when rename!\n");
		uffs_ObjectDevUnLock(obj);
		uffs_CloseObject(obj);
		goto err_exit;
	}

	memcpy(&fi, buf->data, sizeof(uffs_fileInfo));
	if (new_name[new_len-1] == '/') {
		pos = back_search_slash(new_name, new_len - 2);
		len = new_len - 2 - pos;
	}
	else {
		pos = back_search_slash(new_name, new_len - 1);
		len = new_len - 1 - pos;
	}
	memcpy(fi.name, new_name + pos + 1, len);
	fi.name[len] = 0;
	fi.name_len = len;
	fi.lastModify = uffs_GetCurDateTime();

	obj->sum = uffs_MakeSum16(fi.name, fi.name_len);

	//update the check sum of tree node
	if (obj->type == UFFS_TYPE_DIR) {
		obj->node->u.dir.checkSum = obj->sum;
		obj->node->u.dir.father = father_new;
	}
	else {
		obj->node->u.file.checkSum = obj->sum;
		obj->node->u.file.father = father_new;
	}

	buf->father = father_new;	// !! need to manually change the 'father' !!

	uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
	uffs_BufPut(dev, buf);

	uffs_BufFlushEx(dev, U_TRUE);	// !! force a block recover so that all old tag will be expired !!
									// so that we only need to check the first spare when mount UFFS :)

	uffs_ObjectDevUnLock(obj);
	uffs_CloseObject(obj);

	ret = U_SUCC;

err_exit:
	if (obj) uffs_PutObject(obj);
	if (obj_new) uffs_PutObject(obj_new);

	return ret;
}


static URET _LoadObjectInfo(uffs_Device *dev, TreeNode *node, uffs_ObjectInfo *info, int type)
{
	uffs_Buf *buf;

	buf = uffs_BufGetEx(dev, (u8)type, node, 0);

	if(buf == NULL) {
		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;
}

URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info)
{
	uffs_Device *dev = obj->dev;
	URET ret = U_FAIL;

	uffs_ObjectDevLock(obj);

	if (obj && obj->dev && info)
		ret = _LoadObjectInfo(dev, obj->node, info, obj->type);

	uffs_ObjectDevUnLock(obj);

	return ret;
}

/* find objects */
URET uffs_OpenFindObject(uffs_FindInfo *f, const char * dir)
{
	if (f == NULL) return U_FAIL;

	f->obj = uffs_GetObject();
	if (f->obj == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't get a new object\n");
		goto err;
	}

	if (_PrepareOpenObj(f->obj, dir, UO_RDONLY|UO_DIR, US_IREAD|US_IWRITE) == U_FAIL) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"Can't prepare open dir %s for read.\n", dir);
		goto err;
	}

	f->dev = f->obj->dev;

	if (f->obj->nameLen == 0) {
		// This is the root dir !!!, do not try to open it !
		// obj->father and obj->serial should already prepared.
	}
	else {
		uffs_ObjectDevLock(f->obj);
		if (_OpenObjectUnder(f->obj) == U_FAIL) {
			uffs_ObjectDevUnLock(f->obj);
			uffs_Perror(UFFS_ERR_NOISY, PFX"Can't open dir %s, doesn't exist ?\n", dir);
			goto err;
		}
		uffs_ObjectDevUnLock(f->obj);
	}

	f->hash = 0;
	f->work = NULL;
	f->step = 0;

	return U_SUCC;

err:
	if (f->obj) {
		_ReleaseObjectResource(f->obj);
		uffs_PutObject(f->obj);
		f->obj = NULL;
	}

	return U_FAIL;
}

URET uffs_FindFirstObject(uffs_ObjectInfo * info, uffs_FindInfo * f)
{
	uffs_Device *dev = f->dev;
	TreeNode *node;
	u16 x;
	URET ret = U_SUCC;

	uffs_DeviceLock(dev);
	f->step = 0;

	if (f->step == 0) {
		for(f->hash = 0;
			f->hash < DIR_NODE_ENTRY_LEN;
			f->hash++) {

			x = dev->tree.dirEntry[f->hash];

			while(x != EMPTY_NODE) {
				node = FROM_IDX(x, &(dev->tree.dis));
				if(node->u.dir.father == f->obj->serial) {
					f->work = node;
					if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
					uffs_DeviceUnLock(dev);
					return ret;
				}
				x = node->hashNext;
			}
		}

		//no subdirs, then lookup the files
		f->step++;
	}

	if(f->step == 1) {
		for(f->hash = 0;
			f->hash < FILE_NODE_ENTRY_LEN;
			f->hash++) {

			x = dev->tree.fileEntry[f->hash];

			while(x != EMPTY_NODE) {
				node = FROM_IDX(x, &(dev->tree.dis));
				if(node->u.file.father == f->obj->serial) {
					f->work = node;
					if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
					uffs_DeviceUnLock(dev);
					return ret;
				}
				x = node->hashNext;
			}
		}
		f->step++;
	}

	uffs_DeviceUnLock(dev);
	return U_FAIL;
}

URET uffs_FindNextObject(uffs_ObjectInfo *info, uffs_FindInfo * f)
{
	uffs_Device *dev = f->dev;
	TreeNode *node;
	u16 x;
	URET ret = U_SUCC;

	if(f->dev == NULL ||
		f->work == NULL ||
		f->step > 1) return U_FAIL;

	uffs_DeviceLock(dev);

	x = f->work->hashNext;

	if (f->step == 0) { //!< working on dirs
		while(x != EMPTY_NODE) {
			node = FROM_IDX(x, &(dev->tree.dis));
			if(node->u.dir.father == f->obj->serial) {
				f->work = node;
				if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
				uffs_DeviceUnLock(dev);
				return ret;
			}
			x = node->hashNext;
		}

		f->hash++; //come to next hash entry

		for(; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) {
			x = dev->tree.dirEntry[f->hash];
			while(x != EMPTY_NODE) {
				node = FROM_IDX(x, &(dev->tree.dis));
				if(node->u.dir.father == f->obj->serial) {
					f->work = node;
					if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
					uffs_DeviceUnLock(dev);
					return ret;
				}
				x = node->hashNext;
			}
		}

		//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, &(dev->tree.dis));
			if(node->u.file.father == f->obj->serial) {
				f->work = node;
				if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
				uffs_DeviceUnLock(dev);
				return ret;
			}
			x = node->hashNext;
		}

		f->hash++; //come to next hash entry

		for(; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) {
			x = dev->tree.fileEntry[f->hash];
			while(x != EMPTY_NODE) {
				node = FROM_IDX(x, &(dev->tree.dis));
				if(node->u.file.father == f->obj->serial) {
					f->work = node;
					if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
					uffs_DeviceUnLock(dev);
					return ret;
				}
				x = node->hashNext;
			}
		}

		//no any files, stopped.
		f->step++;
	}

	uffs_DeviceUnLock(dev);
	return U_FAIL;
}

URET uffs_CloseFindObject(uffs_FindInfo * f)
{
	if (f == NULL) return U_FAIL;

	if (f->obj) {
		/* close dir */
		_ReleaseObjectResource(f->obj);
		uffs_PutObject(f->obj);
		f->obj = NULL;
	}

	f->dev = NULL;
	f->hash = 0;
	f->work = NULL;

	return U_SUCC;
}


⌨️ 快捷键说明

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