|
|
@@ -15,12 +15,101 @@
|
|
|
#include <dfs_file.h>
|
|
|
#include <dfs_private.h>
|
|
|
|
|
|
+#define DFS_FNODE_HASH_NR 128
|
|
|
+
|
|
|
+struct dfs_fnode_mgr
|
|
|
+{
|
|
|
+ struct rt_mutex lock;
|
|
|
+ rt_list_t head[DFS_FNODE_HASH_NR];
|
|
|
+};
|
|
|
+
|
|
|
+static struct dfs_fnode_mgr dfs_fm;
|
|
|
+
|
|
|
+void dfs_fnode_mgr_init(void)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ rt_mutex_init(&dfs_fm.lock, "dfs_mgr", RT_IPC_FLAG_PRIO);
|
|
|
+ for (i = 0; i < DFS_FNODE_HASH_NR; i++)
|
|
|
+ {
|
|
|
+ rt_list_init(&dfs_fm.head[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* BKDR Hash Function */
|
|
|
+static unsigned int bkdr_hash(const char *str)
|
|
|
+{
|
|
|
+ unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
|
|
|
+ unsigned int hash = 0;
|
|
|
+
|
|
|
+ while (*str)
|
|
|
+ {
|
|
|
+ hash = hash * seed + (*str++);
|
|
|
+ }
|
|
|
+
|
|
|
+ return (hash % DFS_FNODE_HASH_NR);
|
|
|
+}
|
|
|
+
|
|
|
+static struct dfs_fnode *dfs_fnode_find(const char *path, rt_list_t **hash_head)
|
|
|
+{
|
|
|
+ struct dfs_fnode *fnode = NULL;
|
|
|
+ int hash = bkdr_hash(path);
|
|
|
+ rt_list_t *hh;
|
|
|
+
|
|
|
+ hh = dfs_fm.head[hash].next;
|
|
|
+
|
|
|
+ if (hash_head)
|
|
|
+ {
|
|
|
+ *hash_head = &dfs_fm.head[hash];
|
|
|
+ }
|
|
|
+
|
|
|
+ while (hh != &dfs_fm.head[hash])
|
|
|
+ {
|
|
|
+ fnode = rt_container_of(hh, struct dfs_fnode, list);
|
|
|
+ if (rt_strcmp(path, fnode->fullpath) == 0)
|
|
|
+ {
|
|
|
+ /* found */
|
|
|
+ return fnode;
|
|
|
+ }
|
|
|
+ hh = hh->next;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @addtogroup FileApi
|
|
|
*/
|
|
|
|
|
|
/*@{*/
|
|
|
|
|
|
+/**
|
|
|
+ * This function will return whether this file has been opend.
|
|
|
+ *
|
|
|
+ * @param pathname the file path name.
|
|
|
+ *
|
|
|
+ * @return 0 on file has been open successfully, -1 on open failed.
|
|
|
+ */
|
|
|
+int dfs_file_is_open(const char *pathname)
|
|
|
+{
|
|
|
+ char *fullpath = NULL;
|
|
|
+ struct dfs_fnode *fnode = NULL;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ fullpath = dfs_normalize_path(NULL, pathname);
|
|
|
+
|
|
|
+ rt_mutex_take(&dfs_fm.lock, RT_WAITING_FOREVER);
|
|
|
+ fnode = dfs_fnode_find(fullpath, NULL);
|
|
|
+ if (fnode)
|
|
|
+ {
|
|
|
+ ret = 1;
|
|
|
+ }
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+
|
|
|
+ rt_free(fullpath);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* this function will open a file which specified by path with specified flags.
|
|
|
*
|
|
|
@@ -36,6 +125,7 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
|
|
|
char *fullpath;
|
|
|
int result;
|
|
|
struct dfs_fnode *fnode = NULL;
|
|
|
+ rt_list_t *hash_head;
|
|
|
|
|
|
/* parameter check */
|
|
|
if (fd == NULL)
|
|
|
@@ -50,79 +140,110 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
|
|
|
|
|
|
LOG_D("open file:%s", fullpath);
|
|
|
|
|
|
- /* find filesystem */
|
|
|
- fs = dfs_filesystem_lookup(fullpath);
|
|
|
- if (fs == NULL)
|
|
|
+ rt_mutex_take(&dfs_fm.lock, RT_WAITING_FOREVER);
|
|
|
+ /* fnode find */
|
|
|
+ fnode = dfs_fnode_find(fullpath, &hash_head);
|
|
|
+ if (fnode)
|
|
|
{
|
|
|
- rt_free(fullpath); /* release path */
|
|
|
-
|
|
|
- return -ENOENT;
|
|
|
+ fnode->ref_count++;
|
|
|
+ fd->pos = 0;
|
|
|
+ fd->fnode = fnode;
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
}
|
|
|
-
|
|
|
- fnode = rt_calloc(1, sizeof(struct dfs_fnode));
|
|
|
- if (!fnode)
|
|
|
+ else
|
|
|
{
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
- fnode->ref_count = 1;
|
|
|
- fd->fnode = fnode;
|
|
|
+ /* find filesystem */
|
|
|
+ fs = dfs_filesystem_lookup(fullpath);
|
|
|
+ if (fs == NULL)
|
|
|
+ {
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ rt_free(fullpath); /* release path */
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+
|
|
|
+ fnode = rt_calloc(1, sizeof(struct dfs_fnode));
|
|
|
+ if (!fnode)
|
|
|
+ {
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ rt_free(fullpath); /* release path */
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ fnode->ref_count = 1;
|
|
|
|
|
|
- LOG_D("open in filesystem:%s", fs->ops->name);
|
|
|
- fd->fnode->fs = fs; /* set file system */
|
|
|
- fd->fnode->fops = fs->ops->fops; /* set file ops */
|
|
|
+ LOG_D("open in filesystem:%s", fs->ops->name);
|
|
|
+ fnode->fs = fs; /* set file system */
|
|
|
+ fnode->fops = fs->ops->fops; /* set file ops */
|
|
|
|
|
|
- /* initialize the fd item */
|
|
|
- fd->fnode->type = FT_REGULAR;
|
|
|
- fd->fnode->flags = flags;
|
|
|
- fd->fnode->size = 0;
|
|
|
- fd->pos = 0;
|
|
|
- fd->fnode->data = fs;
|
|
|
+ /* initialize the fd item */
|
|
|
+ fnode->type = FT_REGULAR;
|
|
|
+ fnode->flags = flags;
|
|
|
|
|
|
- if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
|
|
|
- {
|
|
|
- if (dfs_subdir(fs->path, fullpath) == NULL)
|
|
|
- fd->fnode->path = rt_strdup("/");
|
|
|
+ if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
|
|
|
+ {
|
|
|
+ if (dfs_subdir(fs->path, fullpath) == NULL)
|
|
|
+ fnode->path = rt_strdup("/");
|
|
|
+ else
|
|
|
+ fnode->path = rt_strdup(dfs_subdir(fs->path, fullpath));
|
|
|
+ LOG_D("Actual file path: %s", fnode->path);
|
|
|
+ }
|
|
|
else
|
|
|
- fd->fnode->path = rt_strdup(dfs_subdir(fs->path, fullpath));
|
|
|
- rt_free(fullpath);
|
|
|
- LOG_D("Actual file path: %s", fd->fnode->path);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- fd->fnode->path = fullpath;
|
|
|
- }
|
|
|
+ {
|
|
|
+ fnode->path = fullpath;
|
|
|
+ }
|
|
|
+ fnode->fullpath = fullpath;
|
|
|
|
|
|
- /* specific file system open routine */
|
|
|
- if (fd->fnode->fops->open == NULL)
|
|
|
- {
|
|
|
- /* clear fd */
|
|
|
- rt_free(fd->fnode->path);
|
|
|
- fd->fnode->path = NULL;
|
|
|
- rt_free(fd->fnode);
|
|
|
- fd->fnode = NULL;
|
|
|
+ /* specific file system open routine */
|
|
|
+ if (fnode->fops->open == NULL)
|
|
|
+ {
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ /* clear fd */
|
|
|
+ if (fnode->path != fnode->fullpath)
|
|
|
+ {
|
|
|
+ rt_free(fnode->fullpath);
|
|
|
+ }
|
|
|
+ rt_free(fnode->path);
|
|
|
+ rt_free(fnode);
|
|
|
|
|
|
- return -ENOSYS;
|
|
|
+ return -ENOSYS;
|
|
|
+ }
|
|
|
+
|
|
|
+ fd->pos = 0;
|
|
|
+ fd->fnode = fnode;
|
|
|
+
|
|
|
+ /* insert fnode to hash */
|
|
|
+ rt_list_insert_after(hash_head, &fnode->list);
|
|
|
}
|
|
|
|
|
|
- if ((result = fd->fnode->fops->open(fd)) < 0)
|
|
|
+ if ((result = fnode->fops->open(fd)) < 0)
|
|
|
{
|
|
|
- /* clear fd */
|
|
|
- rt_free(fd->fnode->path);
|
|
|
- fd->fnode->path = NULL;
|
|
|
- rt_free(fd->fnode);
|
|
|
- fd->fnode = NULL;
|
|
|
+ fnode->ref_count--;
|
|
|
+ if (fnode->ref_count == 0)
|
|
|
+ {
|
|
|
+ /* remove from hash */
|
|
|
+ rt_list_remove(&fnode->list);
|
|
|
+ /* clear fd */
|
|
|
+ if (fnode->path != fnode->fullpath)
|
|
|
+ {
|
|
|
+ rt_free(fnode->fullpath);
|
|
|
+ }
|
|
|
+ rt_free(fnode->path);
|
|
|
+ fd->fnode = NULL;
|
|
|
+ rt_free(fnode);
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ }
|
|
|
|
|
|
LOG_D("%s open failed", fullpath);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- fd->fnode->flags |= DFS_F_OPEN;
|
|
|
+ fnode->flags |= DFS_F_OPEN;
|
|
|
if (flags & O_DIRECTORY)
|
|
|
{
|
|
|
- fd->fnode->type = FT_DIRECTORY;
|
|
|
- fd->fnode->flags |= DFS_F_DIRECTORY;
|
|
|
+ fnode->type = FT_DIRECTORY;
|
|
|
+ fnode->flags |= DFS_F_DIRECTORY;
|
|
|
}
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
|
|
|
LOG_D("open successful");
|
|
|
return 0;
|
|
|
@@ -137,22 +258,52 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
|
|
|
*/
|
|
|
int dfs_file_close(struct dfs_fd *fd)
|
|
|
{
|
|
|
+ struct dfs_fnode *fnode = NULL;
|
|
|
int result = 0;
|
|
|
|
|
|
if (fd == NULL)
|
|
|
+ {
|
|
|
return -ENXIO;
|
|
|
+ }
|
|
|
|
|
|
- if (fd->fnode->fops->close != NULL)
|
|
|
- result = fd->fnode->fops->close(fd);
|
|
|
+ if (fd->ref_count == 1)
|
|
|
+ {
|
|
|
+ rt_mutex_take(&dfs_fm.lock, RT_WAITING_FOREVER);
|
|
|
+ fnode = fd->fnode;
|
|
|
|
|
|
- /* close fd error, return */
|
|
|
- if (result < 0)
|
|
|
- return result;
|
|
|
+ if (fnode->ref_count <= 0)
|
|
|
+ {
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ return -ENXIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fnode->fops->close != NULL)
|
|
|
+ {
|
|
|
+ result = fnode->fops->close(fd);
|
|
|
+ }
|
|
|
|
|
|
- rt_free(fd->fnode->path);
|
|
|
- fd->fnode->path = NULL;
|
|
|
- rt_free(fd->fnode);
|
|
|
- fd->fnode = NULL;
|
|
|
+ /* close fd error, return */
|
|
|
+ if (result < 0)
|
|
|
+ {
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fnode->ref_count == 1)
|
|
|
+ {
|
|
|
+ /* remove from hash */
|
|
|
+ rt_list_remove(&fnode->list);
|
|
|
+ fd->fnode = NULL;
|
|
|
+
|
|
|
+ if (fnode->path != fnode->fullpath)
|
|
|
+ {
|
|
|
+ rt_free(fnode->fullpath);
|
|
|
+ }
|
|
|
+ rt_free(fnode->path);
|
|
|
+ rt_free(fnode);
|
|
|
+ rt_mutex_release(&dfs_fm.lock);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
@@ -169,7 +320,9 @@ int dfs_file_close(struct dfs_fd *fd)
|
|
|
int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
|
|
|
{
|
|
|
if (fd == NULL)
|
|
|
+ {
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
/* regular file system fd */
|
|
|
if (fd->fnode->type == FT_REGULAR || fd->fnode->type == FT_DEVICE)
|
|
|
@@ -192,7 +345,9 @@ int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
|
|
|
}
|
|
|
|
|
|
if (fd->fnode->fops->ioctl != NULL)
|
|
|
+ {
|
|
|
return fd->fnode->fops->ioctl(fd, cmd, args);
|
|
|
+ }
|
|
|
|
|
|
return -ENOSYS;
|
|
|
}
|
|
|
@@ -212,13 +367,19 @@ int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
|
|
|
int result = 0;
|
|
|
|
|
|
if (fd == NULL)
|
|
|
+ {
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
if (fd->fnode->fops->read == NULL)
|
|
|
+ {
|
|
|
return -ENOSYS;
|
|
|
+ }
|
|
|
|
|
|
if ((result = fd->fnode->fops->read(fd, buf, len)) < 0)
|
|
|
+ {
|
|
|
fd->fnode->flags |= DFS_F_EOF;
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
@@ -235,11 +396,20 @@ int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
|
|
|
int dfs_file_getdents(struct dfs_fd *fd, struct dirent *dirp, size_t nbytes)
|
|
|
{
|
|
|
/* parameter check */
|
|
|
- if (fd == NULL || fd->fnode->type != FT_DIRECTORY)
|
|
|
+ if (fd == NULL)
|
|
|
+ {
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fd->fnode->type != FT_DIRECTORY)
|
|
|
+ {
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
if (fd->fnode->fops->getdents != NULL)
|
|
|
+ {
|
|
|
return fd->fnode->fops->getdents(fd, dirp, nbytes);
|
|
|
+ }
|
|
|
|
|
|
return -ENOSYS;
|
|
|
}
|
|
|
@@ -264,17 +434,17 @@ int dfs_file_unlink(const char *path)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- /* get filesystem */
|
|
|
- if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
|
|
|
+ /* Check whether file is already open */
|
|
|
+ if (dfs_file_is_open(fullpath))
|
|
|
{
|
|
|
- result = -ENOENT;
|
|
|
+ result = -EBUSY;
|
|
|
goto __exit;
|
|
|
}
|
|
|
|
|
|
- /* Check whether file is already open */
|
|
|
- if (fd_is_open(fullpath) == 0)
|
|
|
+ /* get filesystem */
|
|
|
+ if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
|
|
|
{
|
|
|
- result = -EBUSY;
|
|
|
+ result = -ENOENT;
|
|
|
goto __exit;
|
|
|
}
|
|
|
|
|
|
@@ -309,10 +479,14 @@ __exit:
|
|
|
int dfs_file_write(struct dfs_fd *fd, const void *buf, size_t len)
|
|
|
{
|
|
|
if (fd == NULL)
|
|
|
+ {
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
if (fd->fnode->fops->write == NULL)
|
|
|
+ {
|
|
|
return -ENOSYS;
|
|
|
+ }
|
|
|
|
|
|
return fd->fnode->fops->write(fd, buf, len);
|
|
|
}
|
|
|
@@ -440,11 +614,10 @@ int dfs_file_stat(const char *path, struct stat *buf)
|
|
|
*/
|
|
|
int dfs_file_rename(const char *oldpath, const char *newpath)
|
|
|
{
|
|
|
- int result;
|
|
|
- struct dfs_filesystem *oldfs, *newfs;
|
|
|
- char *oldfullpath, *newfullpath;
|
|
|
+ int result = RT_EOK;
|
|
|
+ struct dfs_filesystem *oldfs = NULL, *newfs = NULL;
|
|
|
+ char *oldfullpath = NULL, *newfullpath = NULL;
|
|
|
|
|
|
- result = RT_EOK;
|
|
|
newfullpath = NULL;
|
|
|
oldfullpath = NULL;
|
|
|
|
|
|
@@ -455,6 +628,12 @@ int dfs_file_rename(const char *oldpath, const char *newpath)
|
|
|
goto __exit;
|
|
|
}
|
|
|
|
|
|
+ if (dfs_file_is_open((const char *)oldfullpath))
|
|
|
+ {
|
|
|
+ result = -EBUSY;
|
|
|
+ goto __exit;
|
|
|
+ }
|
|
|
+
|
|
|
newfullpath = dfs_normalize_path(NULL, newpath);
|
|
|
if (newfullpath == NULL)
|
|
|
{
|
|
|
@@ -488,8 +667,14 @@ int dfs_file_rename(const char *oldpath, const char *newpath)
|
|
|
}
|
|
|
|
|
|
__exit:
|
|
|
- rt_free(oldfullpath);
|
|
|
- rt_free(newfullpath);
|
|
|
+ if (oldfullpath)
|
|
|
+ {
|
|
|
+ rt_free(oldfullpath);
|
|
|
+ }
|
|
|
+ if (newfullpath)
|
|
|
+ {
|
|
|
+ rt_free(newfullpath);
|
|
|
+ }
|
|
|
|
|
|
/* not at same file system, return EXDEV */
|
|
|
return result;
|
|
|
@@ -527,10 +712,10 @@ int dfs_file_ftruncate(struct dfs_fd *fd, off_t length)
|
|
|
#ifdef RT_USING_FINSH
|
|
|
#include <finsh.h>
|
|
|
|
|
|
-static struct dfs_fd fd;
|
|
|
-static struct dirent dirent;
|
|
|
void ls(const char *pathname)
|
|
|
{
|
|
|
+ struct dfs_fd fd;
|
|
|
+ struct dirent dirent;
|
|
|
struct stat stat;
|
|
|
int length;
|
|
|
char *fullpath, *path;
|
|
|
@@ -552,6 +737,7 @@ void ls(const char *pathname)
|
|
|
path = (char *)pathname;
|
|
|
}
|
|
|
|
|
|
+ fd_init(&fd);
|
|
|
/* list directory */
|
|
|
if (dfs_file_open(&fd, path, O_DIRECTORY) == 0)
|
|
|
{
|
|
|
@@ -610,9 +796,11 @@ FINSH_FUNCTION_EXPORT(rm, remove files or directories);
|
|
|
|
|
|
void cat(const char *filename)
|
|
|
{
|
|
|
- uint32_t length;
|
|
|
+ struct dfs_fd fd;
|
|
|
+ uint32_t length = 0;
|
|
|
char buffer[81];
|
|
|
|
|
|
+ fd_init(&fd);
|
|
|
if (dfs_file_open(&fd, filename, O_RDONLY) < 0)
|
|
|
{
|
|
|
rt_kprintf("Open %s failed\n", filename);
|
|
|
@@ -638,6 +826,7 @@ FINSH_FUNCTION_EXPORT(cat, print file);
|
|
|
#define BUF_SZ 4096
|
|
|
static void copyfile(const char *src, const char *dst)
|
|
|
{
|
|
|
+ struct dfs_fd fd;
|
|
|
struct dfs_fd src_fd;
|
|
|
rt_uint8_t *block_ptr;
|
|
|
rt_int32_t read_bytes;
|
|
|
@@ -650,6 +839,7 @@ static void copyfile(const char *src, const char *dst)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ fd_init(&src_fd);
|
|
|
if (dfs_file_open(&src_fd, src, O_RDONLY) < 0)
|
|
|
{
|
|
|
rt_free(block_ptr);
|
|
|
@@ -657,6 +847,7 @@ static void copyfile(const char *src, const char *dst)
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
+ fd_init(&fd);
|
|
|
if (dfs_file_open(&fd, dst, O_WRONLY | O_CREAT) < 0)
|
|
|
{
|
|
|
rt_free(block_ptr);
|