/** truncate obj without lock device */ static URET do_TruncateObject(uffs_Object *obj, u32 remain, RunOptionE run_opt) { uffs_Device *dev = obj->dev; TreeNode *fnode = obj->node; u16 fdn; u32 flen; u32 block_start; TreeNode *node; uffs_BlockInfo *bc; uffs_Buf *buf; u16 page; int pos; pos = obj->pos; // save current file position if (obj->dev == NULL || obj->open_succ == U_FALSE || fnode == NULL) { obj->err = UEBADF; goto ext; } /* can't truncate a dir */ /* TODO: delete files under dir ? */ if (obj->type == UFFS_TYPE_DIR) { obj->err = UEEXIST; goto ext; } if (remain >= fnode->u.file.len) { goto ext; //!< nothing to do ... } flen = fnode->u.file.len; if (flen < remain) { // file is shorter than 'reamin', fill the gap with '\0' if (run_opt == eREAL_RUN) { obj->pos = flen; // move file pointer to the end if (do_WriteObject(obj, NULL, remain - flen) > 0) { // fill '\0' ... uffs_Perror(UFFS_MSG_SERIOUS, "Write object not finished. expect %d but only %d wrote.", remain - flen, fnode->u.file.len - flen); obj->err = UEIOERR; // likely be an I/O error. } flen = obj->node->u.file.len; } } else { while (flen > remain) { fdn = GetFdnByOfs(obj, flen - 1); //uffs_BufFlushGroup(dev, obj->serial, fdn); //!< flush the buffer block_start = GetStartOfDataBlock(obj, fdn); if (remain <= block_start && fdn > 0) { node = uffs_TreeFindDataNode(dev, obj->serial, fdn); if (node == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "can't find data node when trancate obj."); obj->err = UEIOERR; goto ext; } bc = uffs_BlockInfoGet(dev, node->u.data.block); if (bc == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "can't get block info when trancate obj."); obj->err = UEIOERR; goto ext; } for (page = 0; page < dev->attr->pages_per_block; page++) { buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page); if (buf) { //!< ok, the buffer was loaded before ... if (uffs_BufIsFree(buf) == U_FALSE) { uffs_BlockInfoPut(dev, bc); goto ext; //!< and someone is still holding the buffer, // can't truncate it !!! } else if (run_opt == eREAL_RUN) uffs_BufMarkEmpty(dev, buf); //!< discard the buffer } } if (run_opt == eREAL_RUN) { uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node); uffs_FlashEraseBlock(dev, bc->block); node->u.list.block = bc->block; if (HAVE_BADBLOCK(dev)) uffs_BadBlockProcess(dev, node); else uffs_TreeInsertToErasedListTail(dev, node); fnode->u.file.len = block_start; } flen = block_start; uffs_BlockInfoPut(dev, bc); } else { if (do_TruncateInternalWithBlockRecover(obj, fdn, remain, run_opt) == U_SUCC) { if (run_opt == eREAL_RUN) fnode->u.file.len = remain; flen = remain; } } } } if (HAVE_BADBLOCK(dev)) uffs_BadBlockRecover(dev); ext: obj->pos = pos; // keep file pointer offset not changed. uffs_Assert(fnode == obj->node, "obj->node change!\n"); return (obj->err == UENOERR ? U_SUCC : U_FAIL); }
/** truncate obj without lock device */ static URET do_TruncateObject(uffs_Object *obj, u32 remain, UBOOL dry_run) { uffs_Device *dev = obj->dev; TreeNode *fnode = obj->node; u16 fdn; u32 flen; u32 block_start; TreeNode *node; uffs_BlockInfo *bc; uffs_Buf *buf; u16 page; if (obj->dev == NULL || obj->open_succ == U_FALSE || fnode == NULL) { obj->err = UEBADF; goto ext; } /* can't truncate a dir */ /* TODO: delete files under dir ? */ if (obj->type == UFFS_TYPE_DIR) { obj->err = UEEXIST; goto ext; } if (remain >= fnode->u.file.len) { goto ext; //!< nothing to do ... } flen = fnode->u.file.len; while (flen > remain) { fdn = GetFdnByOfs(obj, flen - 1); //uffs_BufFlushGroup(dev, obj->serial, fdn); //!< flush the buffer block_start = GetStartOfDataBlock(obj, fdn); if (remain <= block_start && fdn > 0) { node = uffs_TreeFindDataNode(dev, obj->serial, fdn); if (node == NULL) { uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node when trancate obj."); obj->err = UEIOERR; goto ext; } bc = uffs_BlockInfoGet(dev, node->u.data.block); if (bc == NULL) { uffs_Perror(UFFS_ERR_SERIOUS, "can't get block info when trancate obj."); obj->err = UEIOERR; goto ext; } for (page = 0; page < dev->attr->pages_per_block; page++) { buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page); if (buf) { //!< ok, the buffer was loaded before ... if (uffs_BufIsFree(buf) == U_FALSE) { uffs_BlockInfoPut(dev, bc); goto ext; //!< and someone is still holding the buffer, can't truncate it !!! } else if (dry_run == U_FALSE) uffs_BufMarkEmpty(dev, buf); //!< discard the buffer } } if (dry_run == U_FALSE) { uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES); uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node); uffs_FlashEraseBlock(dev, bc->block); node->u.list.block = bc->block; if (HAVE_BADBLOCK(dev)) uffs_BadBlockProcess(dev, node); else uffs_TreeInsertToErasedListTail(dev, node); uffs_BlockInfoPut(dev, bc); fnode->u.file.len = block_start; } else { uffs_BlockInfoPut(dev, bc); } flen = block_start; } else { if (do_TruncateInternalWithBlockRecover(obj, fdn, remain, dry_run) == U_SUCC) { if (dry_run == U_FALSE) fnode->u.file.len = remain; flen = remain; } } } if (HAVE_BADBLOCK(dev)) uffs_BadBlockRecover(dev); ext: return (obj->err == UENOERR ? U_SUCC : U_FAIL); }