/** * write data to obj, return remain data (0 if all data been written). */ static int do_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; while (remain > 0) { write_start = obj->pos + len - remain; if (write_start > fnode->u.file.len) { uffs_Perror(UFFS_MSG_SERIOUS, "write point out of file ?"); break; } fdn = GetFdnByOfs(obj, write_start); if (write_start == fnode->u.file.len && fdn > 0 && write_start == GetStartOfDataBlock(obj, fdn)) { if (dev->tree.erased_count < dev->cfg.reserved_free_blocks) { uffs_Perror(UFFS_MSG_NOISY, "insufficient block in write obj, new block"); break; } size = do_WriteNewBlock(obj, data ? (u8 *)data + len - remain : NULL, remain, fnode->u.file.serial, fdn); // // Flush the new block buffers immediately, so that the new data node will be // created and put in the tree. // // But before do that, we need to make sure the previous // data block (if exist) been flushed first. // if (fdn > 1) { uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn - 1); } else { uffs_BufFlushGroup(dev, fnode->u.file.parent, fnode->u.file.serial); } // Now flush the new block. uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn); if (size == 0) break; remain -= size; } else { if(fdn == 0) dnode = obj->node; else dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn); if(dnode == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "can't find data node in tree ?"); obj->err = UEUNKNOWN_ERR; break; } size = do_WriteInternalBlock(obj, dnode, fdn, data ? (u8 *)data + len - remain : NULL, remain, write_start - GetStartOfDataBlock(obj, fdn)); #ifdef CONFIG_FLUSH_BUF_AFTER_WRITE if (fdn == 0) uffs_BufFlushGroup(dev, fnode->u.file.parent, fnode->u.file.serial); else uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn); #endif if (size == 0) break; remain -= size; } } uffs_Assert(fnode == obj->node, "obj->node change!\n"); return remain; }
/** * 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->open_succ != U_TRUE) { obj->err = UEBADF; return 0; } if (obj->type == UFFS_TYPE_DIR) { uffs_Perror(UFFS_ERR_NOISY, "Can't write to an dir object!"); obj->err = UEACCES; return 0; } if (obj->pos > fnode->u.file.len) { return 0; //can't write file out of range } if (obj->oflag == UO_RDONLY) { obj->err = UEACCES; 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, "write point out of file ?"); break; } fdn = GetFdnByOfs(obj, write_start); if (write_start == fnode->u.file.len && fdn > 0 && write_start == GetStartOfDataBlock(obj, fdn)) { if (dev->tree.erased_count < MINIMUN_ERASED_BLOCK) { uffs_Perror(UFFS_ERR_NOISY, "insufficient block in write obj, new block"); break; } size = do_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_BufFlushGroup(dev, fnode->u.file.serial, fdn); if (size == 0) break; remain -= size; } else { if(fdn == 0) dnode = obj->node; else dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn); if(dnode == NULL) { uffs_Perror(UFFS_ERR_SERIOUS, "can't find data node in tree ?"); obj->err = UEUNKNOWN; break; } size = do_WriteInternalBlock(obj, dnode, fdn, (u8 *)data + len - remain, remain, write_start - GetStartOfDataBlock(obj, fdn)); #ifdef CONFIG_FLUSH_BUF_AFTER_WRITE uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn); #endif if (size == 0) break; remain -= size; } } obj->pos += (len - remain); if (HAVE_BADBLOCK(dev)) uffs_BadBlockRecover(dev); uffs_ObjectDevUnLock(obj); return len - remain; }