📄 uffs_fs.c
字号:
/*
Copyright (C) 2005-2008 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* \file uffs_fs.c
* \brief basic file operations
* \author Ricky Zheng, created 12th May, 2005
*/
#include "uffs/uffs_fs.h"
#include "uffs/uffs_config.h"
#include "uffs/ubuffer.h"
#include "uffs/uffs_ecc.h"
#include "uffs/uffs_badblock.h"
#include "uffs/uffs_os.h"
#include <string.h>
#include <stdio.h>
#define PFX "fs:"
#define GET_SERIAL_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.serial : (obj)->node->u.file.serial)
#define GET_BLOCK_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.block : (obj)->node->u.file.block)
static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode);
static URET _CreateObjectUnder(uffs_Object *obj);
static void _ReleaseObjectResource(uffs_Object *obj);
static URET _TruncateObject(uffs_Object *obj, u32 remain);
static int _object_buf[sizeof(uffs_Object) * MAX_OBJECT_HANDLE / sizeof(int)];
static struct ubufm _object_dis = {
_object_buf,
sizeof(uffs_Object),
MAX_OBJECT_HANDLE,
NULL,
0,
};
/**
* initialise object buffers, called by UFFS internal
*/
URET uffs_InitObjectBuf(void)
{
if(uBufInit(&_object_dis) < 0) return U_FAIL;
else return U_SUCC;
}
/**
* Release object buffers, called by UFFS internal
*/
URET uffs_ReleaseObjectBuf(void)
{
return uBufRelease(&_object_dis) < 0 ? U_FAIL : U_SUCC;
}
/**
* alloc a new object structure
* \return the new object
*/
uffs_Object * uffs_GetObject(void)
{
uffs_Object * obj;
obj = (uffs_Object *)uBufGet(&_object_dis);
if (obj) {
memset(obj, 0, sizeof(uffs_Object));
obj->openSucc = U_FALSE;
}
return obj;
}
/**
* put the object struct back to system
*/
void uffs_PutObject(uffs_Object *obj)
{
if(obj) uBufPut(obj, &_object_dis);
}
/**
* \return the internal index num of object
*/
int uffs_GetObjectIndex(uffs_Object *obj)
{
return uBufGetIndex(obj, &_object_dis);
}
/**
* \return the object by the internal index
*/
uffs_Object * uffs_GetObjectByIndex(int idx)
{
return (uffs_Object *) uBufGetBufByIndex(idx, &_object_dis);
}
static void uffs_ObjectDevLock(uffs_Object *obj)
{
if (obj) {
if (obj->dev) {
uffs_DeviceLock(obj->dev);
obj->devLockCount++;
}
}
}
static void uffs_ObjectDevUnLock(uffs_Object *obj)
{
if (obj) {
if (obj->dev) {
obj->devLockCount--;
uffs_DeviceUnLock(obj->dev);
}
}
}
/** get path from fullname, return path length
* fullname: "/abc/def" | "/abc/def/" | "/"
* ==> path: "/abc/" | "/abc/def/" | "/"
*/
static int _getpath(const char *fullname, char *path)
{
int i;
int len;
if (fullname[0] == 0) return 0;
len = strlen(fullname);
for (i = len - 1; i > 0 && fullname[i] != '/'; i--);
i++;
if (path) {
memcpy(path, fullname, i);
path[i] = 0;
}
return i;
}
/** get name from fullname
* fullname: "/abc/def" | "/abc/def/" | "/"
* returen: "def" | "" | ""
*/
static const char * _getname(const char *fullname)
{
int pos = _getpath(fullname, NULL);
return fullname + pos;
}
static int forwad_search_slash(const char *str, int pos)
{
int len = strlen(str);
while(str[pos] != '/' && pos < len) pos++;
if (pos == len)
return -1;
else
return pos;
}
static int back_search_slash(const char *str, int pos)
{
while (str[pos] != '/' && pos >= 0) pos--;
return pos;
}
/**
* create a new object and open it if success
*/
URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag, int pmode)
{
URET ret = U_FAIL;
oflag |= UO_CREATE;
if (_PrepareOpenObj(obj, fullname, oflag, pmode) == U_SUCC) {
uffs_ObjectDevLock(obj);
ret = _CreateObjectUnder(obj);
uffs_ObjectDevUnLock(obj);
}
return ret;
}
/** find the matched mount point from path */
static int find_maxMatchedMountPoint(const char *path)
{
char buf[MAX_PATH_LENGTH+1] = {0};
int pos;
uffs_Device *dev;
pos = strlen(path);
memcpy(buf, path, pos + 1);
while(pos > 0) {
if ((dev = uffs_GetDevice(buf)) != NULL ) {
uffs_PutDevice(dev);
return pos;
}
else {
buf[pos - 1] = '\0'; //replace the last '/' with '\0'
//back forward search the next '/'
for (; pos > 0 && buf[pos-1] != '/'; pos--)
buf[pos-1] = '\0';
}
}
return pos;
}
static URET _CreateObjectUnder(uffs_Object *obj)
{
/**
* \note: level 0 has been set in obj.
*/
uffs_Buf *buf = NULL;
uffs_fileInfo fi, *pfi;
URET ret;
TreeNode *node;
if (obj->type == UFFS_TYPE_DIR) {
//find out whether have file with the same name
node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
if (node != NULL) {
obj->err = UEEXIST;
return U_FAIL;
}
obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
}
else {
//find out whether have dir with the same name
node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
if (node != NULL) {
obj->err = UEEXIST;
return U_FAIL;
}
obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
}
if (obj->node) {
/* dir|file already exist, truncate it to zero length */
obj->serial = GET_SERIAL_FROM_NODE(obj);
buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);
if(buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"found in tree, but can' load buffer ?\n");
goto err;
}
pfi = (uffs_fileInfo *)(buf->data);
obj->access = pfi->access;
obj->attr = pfi->attr;
obj->createTime = pfi->createTime;
obj->lastModify = pfi->lastModify;
uffs_BufPut(obj->dev, buf);
obj->pos = 0;
obj->openSucc = U_TRUE;
ret = _TruncateObject(obj, 0);
if (ret != U_SUCC) {
obj->openSucc = U_FALSE;
}
return ret;
}
/* dir|file does not exist, create a new one */
obj->serial = uffs_FindFreeFsnSerial(obj->dev);
if (obj->serial == INVALID_UFFS_SERIAL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"No free serial num!\n");
goto err;
}
if(obj->dev->tree.erasedCount < MINIMUN_ERASED_BLOCK) {
uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient block in create obj\n");
goto err;
}
buf = uffs_BufNew(obj->dev, obj->type, obj->father, obj->serial, 0);
if(buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't new buffer when create obj!\n");
goto err;
}
memset(&fi, 0, sizeof(uffs_fileInfo));
memcpy(fi.name, obj->name, obj->nameLen);
fi.name[obj->nameLen] = '\0';
fi.name_len = obj->nameLen;
fi.access = 0;
fi.attr |= FILE_ATTR_WRITE;
if (obj->type == UFFS_TYPE_DIR)
fi.attr |= FILE_ATTR_DIR;
fi.createTime = fi.lastModify = uffs_GetCurDateTime();
obj->createTime = fi.createTime;
obj->lastModify = fi.lastModify;
obj->attr = fi.attr;
obj->access = fi.access;
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_BufFlush(obj->dev);
//update obj->node: after buf flushed, the NEW node can be found in the tree
if (obj->type == UFFS_TYPE_DIR)
obj->node = uffs_FindDirNodeFromTree(obj->dev, obj->serial);
else
obj->node = uffs_FindFileNodeFromTree(obj->dev, obj->serial);
if(obj->node == NULL) {
uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find the node in the tree ?\n");
goto err;
}
if (obj->type == UFFS_TYPE_DIR) {
//do nothing for dir ...
}
else {
obj->node->u.file.len = 0; //init the length to 0
}
if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
obj->openSucc = U_TRUE;
return U_SUCC;
err:
if (buf && obj->dev) {
uffs_BufPut(obj->dev, buf);
buf = NULL;
}
return U_FAIL;
}
static URET _OpenObjectUnder(uffs_Object *obj)
{
uffs_Buf *buf = NULL;
uffs_fileInfo *fi = NULL;
/*************** init level 1 ***************/
if (obj->type == UFFS_TYPE_DIR) {
obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
}
else {
obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
}
if(obj->node == NULL) {
/* dir|file not exist */
if(obj->oflag & UO_CREATE){
//create dir|file
return _CreateObjectUnder(obj);
}
else {
obj->err = UENOENT;
//uffs_Perror(UFFS_ERR_NOISY, PFX"dir or file not found\n");
return U_FAIL;
}
}
obj->serial = GET_SERIAL_FROM_NODE(obj);
buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);
if(buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buf when open!\n");
return U_FAIL;
}
fi = (uffs_fileInfo *)(buf->data);
obj->attr = fi->attr;
obj->createTime = fi->createTime;
obj->lastModify = fi->lastModify;
obj->access = fi->access;
uffs_BufPut(obj->dev, buf);
if((obj->oflag & (UO_CREATE | UO_EXCL)) == (UO_CREATE | UO_EXCL)){
obj->err = UEEXIST;
return U_FAIL;
}
obj->openSucc = U_TRUE;
if(obj->oflag & UO_TRUNC) {
if(_TruncateObject(obj, 0) == U_FAIL){
//obj->err will be set in _TruncateObject
return U_FAIL;
}
}
obj->err = UENOERR;
return U_SUCC;
}
/**
* \brief search '/' in path from *pos
* \param path the string to be search
* \param pos[in/out] search start position, *pos will be updated after search
* \return matched length
*/
static int getPathPart(const char *path, int *pos)
{
int len = 0;
for (len = 0; path[len+(*pos)] != '\0' && path[len+(*pos)] != '/'; len++) ;
*pos += len;
return len;
}
/** get dir's serial No.
* path is the relative path from mount point: "abc/def/" | "" (in this case, return father)
*/
static u16 _GetDirSerial(uffs_Device *dev, const char *path, u16 father)
{
int pos = 0;
int pos_last = 0;
int len = 0;
char part[MAX_FILENAME_LENGTH+1] = {0};
TreeNode * node;
u16 sum;
u16 serial = father;
while((len = getPathPart(path, &pos)) > 0) {
memcpy(part, path + pos_last, len);
part[len] = '\0';
sum = uffs_MakeSum16(part, len);
node = uffs_FindDirNodeByName(dev, part, len, sum, serial);
if (node) {
serial = node->u.dir.serial;
pos_last = ++pos;
}
else {
return INVALID_UFFS_SERIAL;
}
}
return serial;
}
/** prepare the object struct for open */
static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode)
{
char buf[MAX_PATH_LENGTH+1] = {0};
char mount[MAX_FILENAME_LENGTH+1] = {0};
char *start_path = mount;
int pos;
int i, len;
u8 type;
type = (oflag & UO_DIR) ? UFFS_TYPE_DIR : UFFS_TYPE_FILE;
obj->dev = NULL;
if((oflag & (UO_WRONLY | UO_RDWR)) == (UO_WRONLY | UO_RDWR)){
/* UO_WRONLY and UO_RDWR can't appear together */
uffs_Perror(UFFS_ERR_NOISY, PFX"UO_WRONLY and UO_RDWR can't appear together\n");
obj->err = UEINVAL;
return U_FAIL;
}
obj->pos = 0;
if (!fullname) {
uffs_Perror(UFFS_ERR_NOISY, PFX"bad file/dir name: %s\n", fullname);
obj->err = UEINVAL;
return U_FAIL;
}
/************** init level 0 **************/
obj->oflag = oflag;
obj->pmode = pmode;
len = strlen(fullname);
if (oflag & UO_DIR) {
/** open a directory */
obj->type = UFFS_TYPE_DIR;
// dir name should end with '/'
if (fullname[len-1] != '/') {
uffs_Perror(UFFS_ERR_NOISY, PFX"bad dir name: %s\n", fullname);
obj->err = UEINVAL;
return U_FAIL;
}
}
else {
/** open a file */
obj->type = UFFS_TYPE_FILE;
if (fullname[len-1] == '/') {
uffs_Perror(UFFS_ERR_NOISY, PFX"bad file name: %s\n", fullname);
obj->err = UEINVAL;
return U_FAIL;
}
}
_getpath(fullname, buf);
// get path from full name, now what's on buf:
// if it's dir: "/abc/def/xyz/" | "/abc/" | "/abc/" | "/"
// if it's file: "/abc/def/" | X | "/" | X
pos = find_maxMatchedMountPoint(buf);
if (pos == 0) {
/* can't not find any mount point from the path ??? */
uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find any mount point from the path %s\n", buf);
obj->err = UENOENT;
return U_FAIL;
}
// get mount point: "/abc/" or "/"
memcpy(mount, buf, pos);
mount[pos] = '\0';
obj->dev = uffs_GetDevice(mount);
if (obj->dev == NULL) {
// uffs_Perror(UFFS_ERR_NOISY, "Can't get device from mount point: %s\r\n", mount);
obj->err = UENOENT;
return U_FAIL;
}
//here is a good chance to deal with bad block ...
if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
// get the rest name (fullname - mount point) to buf:
// if the mount point is "/abc/", then:
// if it's dir: "def/xyz/" | "" | "" | X
// if it's file: "def/xyz" | X | X | X
// if the mount point is "/", then:
// if it's dir: "abc/def/xyz/ | "abc/" | "abc/" | ""
// if it's file: "abc/def/xyz" | X | "abc" | X
len = strlen(fullname) - strlen(mount);
memcpy(buf, fullname + strlen(mount), len);
buf[len] = '\0';
if (len == 0 && (oflag & UO_DIR) == 0) {
uffs_Perror(UFFS_ERR_NOISY, PFX"bad file name: %s\n", fullname);
obj->err = UEINVAL;
goto err;
}
if (oflag & UO_DIR) {
if (len == 0) {
// uffs_Perror(UFFS_ERR_NOISY, "Zero length name ? root dir ?\r\n");
obj->father = PARENT_OF_ROOT;
obj->serial = ROOT_DIR_ID;
obj->nameLen = 0;
}
else {
if (buf[len-1] == '/') {
buf[len-1] = 0;
len--;
}
for (i = len - 1; i >= 0 && buf[i] != '/'; i--);
obj->nameLen = len - i - 1;
strcpy(obj->name, buf + i + 1);
if (i < 0) {
obj->father = ROOT_DIR_ID;
}
else {
buf[i+1] = 0;
obj->father = _GetDirSerial(obj->dev, buf, ROOT_DIR_ID);
}
}
}
else {
for(i = len - 1; i >= 0 && buf[i] != '/'; i--);
obj->nameLen = len - i - 1;
strcpy(obj->name, buf + i + 1);
if (i < 0) {
obj->father = ROOT_DIR_ID;
}
else {
buf[i+1] = 0;
obj->father = _GetDirSerial(obj->dev, buf, ROOT_DIR_ID);
}
}
if (obj->father == INVALID_UFFS_SERIAL) {
uffs_Perror(UFFS_ERR_NORMAL, PFX"can't open path %s\n", start_path);
obj->err = UENOENT;
goto err;
}
obj->sum = uffs_MakeSum16(obj->name, obj->nameLen);
obj->encode = UFFS_DEFAULT_ENCODE;
obj->pagesOnHead = obj->dev->attr->pages_per_block - 1;
//uffs_Perror(UFFS_ERR_NOISY, "Prepare name: %s\r\n", obj->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -