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