📄 uffs_fs.c
字号:
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 + -