/** * find a node from tree * \param[in] dev uffs device * \param[in] type type of node * \param[in] parent parent serial num * \param[in] serial serial num */ TreeNode * uffs_FindFromTree(uffs_Device *dev, u8 type, u16 parent, u16 serial) { switch (type) { case UFFS_TYPE_DIR: return uffs_TreeFindDirNode(dev, serial); case UFFS_TYPE_FILE: return uffs_TreeFindFileNode(dev, serial); case UFFS_TYPE_DATA: return uffs_TreeFindDataNode(dev, parent, serial); } uffs_Perror(UFFS_MSG_SERIOUS, "unkown type, can't find node"); return NULL; }
/** * Open a FindInfo for finding objects under dir * * \param[out] f uffs_FindInfo structure * \param[in] dev uffs device * \param[in] dir serial number of the dir to be searched * * \return U_SUCC if success, U_FAIL if invalid param or the dir * serial number is not valid. */ URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir) { TreeNode *node; if (f == NULL || dev == NULL) return U_FAIL; node = uffs_TreeFindDirNode(dev, dir); if (node == NULL) return U_FAIL; f->serial = dir; f->dev = dev; ResetFindInfo(f); return U_SUCC; }
/** * find a free file or dir serial NO * \param[in] dev uffs device * \return if no free serial found, return #INVALID_UFFS_SERIAL */ u16 uffs_FindFreeFsnSerial(uffs_Device *dev) { u16 i; TreeNode *node; //TODO!! Do we need a faster serial number generating method? // it depends on how often creating files or directories for (i = ROOT_DIR_SERIAL + 1; i < MAX_UFFS_FSN; i++) { node = uffs_TreeFindDirNode(dev, i); if (node == NULL) { node = uffs_TreeFindFileNode(dev, i); if (node == NULL) { node = uffs_TreeFindSuspendNode(dev, i); if (node == NULL) return i; } } } return INVALID_UFFS_SERIAL; }
/** * Create an object under the given dir. * * \param[in|out] obj to be created, obj is returned from uffs_GetObject() * \param[in] dev uffs device * \param[in] dir object parent dir serial NO. * \param[in] name point to the object name * \param[in] name_len object name length * \param[in] oflag open flag. UO_DIR should be passed for an dir object. * * \return U_SUCC or U_FAIL (error code in obj->err). */ URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev, int dir, const char *name, int name_len, int oflag) { uffs_Buf *buf = NULL; uffs_FileInfo fi; TreeNode *node; obj->dev = dev; obj->parent = dir; obj->type = (oflag & UO_DIR ? UFFS_TYPE_DIR : UFFS_TYPE_FILE); obj->name = name; obj->name_len = name_len; if (obj->type == UFFS_TYPE_DIR) { if (name[obj->name_len - 1] == '/') // get rid of ending '/' for dir obj->name_len--; } else { if (name[obj->name_len - 1] == '/') { // file name can't end with '/' obj->err = UENOENT; goto ext; } } if (obj->name_len == 0) { // empty name ? obj->err = UENOENT; goto ext; } obj->sum = uffs_MakeSum16(obj->name, obj->name_len); uffs_ObjectDevLock(obj); if (obj->type == UFFS_TYPE_DIR) { //find out whether have file with the same name node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent); if (node != NULL) { obj->err = UEEXIST; // we can't create a dir has the // same name with exist file. goto ext_1; } obj->node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent); if (obj->node != NULL) { obj->err = UEEXIST; // we can't create a dir already exist. goto ext_1; } } else { //find out whether have dir with the same name node = uffs_TreeFindDirNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent); if (node != NULL) { obj->err = UEEXIST; goto ext_1; } obj->node = uffs_TreeFindFileNodeByName(obj->dev, obj->name, obj->name_len, obj->sum, obj->parent); if (obj->node) { /* file already exist, truncate it to zero length */ obj->serial = GET_OBJ_NODE_SERIAL(obj); obj->open_succ = U_TRUE; // set open_succ to U_TRUE before // call do_TruncateObject() if (do_TruncateObject(obj, 0, eDRY_RUN) == U_SUCC) do_TruncateObject(obj, 0, eREAL_RUN); goto ext_1; } } /* dir|file does not exist, create a new one */ obj->serial = uffs_FindFreeFsnSerial(obj->dev); if (obj->serial == INVALID_UFFS_SERIAL) { uffs_Perror(UFFS_MSG_SERIOUS, "No free serial num!"); obj->err = UENOMEM; goto ext_1; } if (obj->dev->tree.erased_count < obj->dev->cfg.reserved_free_blocks) { uffs_Perror(UFFS_MSG_NOISY, "insufficient block in create obj"); obj->err = UENOMEM; goto ext_1; } buf = uffs_BufNew(obj->dev, obj->type, obj->parent, obj->serial, 0); if (buf == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "Can't create new buffer when create obj!"); goto ext_1; } memset(&fi, 0, sizeof(uffs_FileInfo)); fi.name_len = obj->name_len < sizeof(fi.name) ? obj->name_len : sizeof(fi.name) - 1; memcpy(fi.name, obj->name, fi.name_len); fi.name[fi.name_len] = '\0'; fi.access = 0; fi.attr |= FILE_ATTR_WRITE; if (obj->type == UFFS_TYPE_DIR) fi.attr |= FILE_ATTR_DIR; fi.create_time = fi.last_modify = uffs_GetCurDateTime(); uffs_BufWrite(obj->dev, buf, &fi, 0, sizeof(uffs_FileInfo)); uffs_BufPut(obj->dev, buf); // flush buffer immediately, // so that the new node will be inserted into the tree uffs_BufFlushGroup(obj->dev, obj->parent, obj->serial); // update obj->node: after buf flushed, // the NEW node can be found in the tree if (obj->type == UFFS_TYPE_DIR) obj->node = uffs_TreeFindDirNode(obj->dev, obj->serial); else obj->node = uffs_TreeFindFileNode(obj->dev, obj->serial); if (obj->node == NULL) { uffs_Perror(UFFS_MSG_NOISY, "Can't find the node in the tree ?"); obj->err = UEIOERR; goto ext_1; } if (obj->type == UFFS_TYPE_FILE) obj->node->u.file.len = 0; //init the length to 0 if (HAVE_BADBLOCK(obj->dev)) uffs_BadBlockRecover(obj->dev); obj->open_succ = U_TRUE; ext_1: uffs_ObjectDevUnLock(obj); ext: return (obj->err == UENOERR ? U_SUCC : U_FAIL); }