summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
author[email protected] <[email protected]>2011-10-17 11:33:30 +0000
committer[email protected] <[email protected]>2011-10-17 11:33:30 +0000
commitf66dafe7a65e8203564a4fb9b4176170737e40ac (patch)
tree9cba29297dd8cd4d91ccd5877158df0902e823e7 /components
parent3d9e766c8641ce4b685c07fc1e6e0bfa31953469 (diff)
fix lseek underflow problem
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1767 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'components')
-rw-r--r--components/dfs/src/dfs_posix.c1341
1 files changed, 673 insertions, 668 deletions
diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c
index f3e6a3edfd..97c8ccd83e 100644
--- a/components/dfs/src/dfs_posix.c
+++ b/components/dfs/src/dfs_posix.c
@@ -1,668 +1,673 @@
-/*
- * File : dfs_posix.c
- * This file is part of Device File System in RT-Thread RTOS
- * COPYRIGHT (C) 2004-2010, RT-Thread Development Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE.
- *
- * Change Logs:
- * Date Author Notes
- * 2009-05-27 Yi.qiu The first version
- */
-
-#include <dfs.h>
-#include <dfs_posix.h>
-
-/**
- * @addtogroup FsPosixApi
- */
-/*@{*/
-
-/**
- * this function is a POSIX compliant version, which will open a file and return
- * a file descriptor.
- *
- * @param file the path name of file.
- * @param flags the file open flags.
- * @param mode
- *
- * @return the non-negative integer on successful open, others for failed.
- */
-int open(const char *file, int flags, int mode)
-{
- int fd, result;
- struct dfs_fd* d;
-
- /* allocate a fd */
- fd = fd_new();
- if (fd < 0) return -1;
- d = fd_get(fd);
-
- result = dfs_file_open(d, file, flags);
- if (result < 0)
- {
- rt_set_errno(result);
-
- /* release the ref-count of fd */
- fd_put(d);
- fd_put(d);
-
- return -1;
- }
-
- /* release the ref-count of fd */
- fd_put(d);
- return fd;
-}
-
-/**
- * this function is a POSIX compliant version, which will close the open
- * file descriptor.
- *
- * @param fd the file descriptor.
- *
- * @return 0 on successful, -1 on failed.
- */
-int close(int fd)
-{
- int result;
- struct dfs_fd* d;
-
- d = fd_get(fd);
- if (d == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- result = dfs_file_close(d);
- fd_put(d);
-
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
-
- fd_put(d);
- return 0;
-}
-
-/**
- * this function is a POSIX compliant version, which will read specified data buffer
- * length for an open file descriptor.
- *
- * @param fd the file descriptor.
- * @param buf the buffer to save the read data.
- * @param len the maximal length of data buffer
- *
- * @return the actual read data buffer length
- */
-int read(int fd, void *buf, size_t len)
-{
- int result;
- struct dfs_fd* d;
-
- /* get the fd */
- d = fd_get(fd);
- if (d == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- result = dfs_file_read(d, buf, len);
- if (result < 0)
- {
- rt_set_errno(result);
- fd_put(d);
-
- return -1;
- }
-
- /* release the ref-count of fd */
- fd_put(d);
- return result;
-}
-
-/**
- * this function is a POSIX compliant version, which will write pecified data buffer
- * length for an open file descriptor.
- *
- * @param fd the file descriptor
- * @param buf the data buffer to be written.
- * @param len the data buffer length.
- *
- * @return the actual written data buffer length.
- */
-int write(int fd, const void *buf, size_t len)
-{
- int result;
- struct dfs_fd* d;
-
- /* get the fd */
- d = fd_get(fd);
- if (d == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- result = dfs_file_write(d, buf, len);
- if (result < 0)
- {
- rt_set_errno(result);
- fd_put(d);
-
- return -1;
- }
-
- /* release the ref-count of fd */
- fd_put(d);
- return result;
-}
-
-/**
- * this function is a POSIX compliant version, which will seek the offset for an
- * open file descriptor.
- *
- * @param fd the file descriptor.
- * @param offset the offset to be seeked.
- * @param whence the directory of seek.
- *
- * @return the current file position, or -1 on failed.
- */
-off_t lseek(int fd, off_t offset, int whence)
-{
- int result;
- struct dfs_fd* d;
-
- d = fd_get(fd);
- if (d == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- switch (whence)
- {
- case DFS_SEEK_SET:
- break;
-
- case DFS_SEEK_CUR:
- offset += d->pos;
- break;
-
- case DFS_SEEK_END:
- offset += d->size;
- break;
- }
-
- result = dfs_file_lseek(d, offset);
- if (result < 0)
- {
- rt_set_errno(result);
- fd_put(d);
- return -1;
- }
-
- /* release the ref-count of fd */
- fd_put(d);
- return offset;
-}
-
-/**
- * this function is a POSIX compliant version, which will rename old file name to
- * new file name.
- *
- * @param old the old file name.
- * @param new the new file name.
- *
- * @return 0 on successful, -1 on failed.
- *
- * note: the old and new file name must be belong to a same file system.
- */
-int rename(const char* old, const char* new)
-{
- int result;
-
- result = dfs_file_rename(old, new);
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
- return 0;
-}
-
-/**
- * this function is a POSIX compliant version, which will unlink (remove) a
- * specified path file from file system.
- *
- * @param pathname the specified path name to be unlinked.
- *
- * @return 0 on successful, -1 on failed.
- */
-int unlink(const char *pathname)
-{
- int result;
-
- result = dfs_file_unlink(pathname);
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
- return 0;
-}
-
-/**
- * this function is a POSIX compliant version, which will get file information.
- *
- * @param file the file name
- * @param buf the data buffer to save stat description.
- *
- * @return 0 on successful, -1 on failed.
- */
-int stat(const char *file, struct stat *buf)
-{
- int result;
-
- result = dfs_file_stat(file, buf);
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
- return result;
-}
-
-/**
- * this function is a POSIX compliant version, which will get file status.
- *
- * @param fildes the file description
- * @param buf the data buffer to save stat description.
- */
-int fstat(int fildes, struct stat *buf)
-{
- struct dfs_fd* d;
-
- /* get the fd */
- d = fd_get(fildes);
- if (d == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- /* it's the root directory */
- buf->st_dev = 0;
-
- buf->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
- DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
- if (d->type == FT_DIRECTORY)
- {
- buf->st_mode &= ~DFS_S_IFREG;
- buf->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
- }
-
- buf->st_size = d->size;
- buf->st_mtime = 0;
- buf->st_blksize = 512;
-
- fd_put(d);
-
- return DFS_STATUS_OK;
-}
-
-/**
- * this function is a POSIX compliant version, which will return the
- * information about a mounted file system.
- *
- * @param path the path which mounted file system.
- * @param buf the buffer to save the returned information.
- *
- * @return 0 on successful, others on failed.
- */
-int statfs(const char *path, struct statfs *buf)
-{
- int result;
-
- result = dfs_statfs(path, buf);
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
-
- return result;
-}
-
-/**
- * this function is a POSIX compliant version, which will make a directory
- *
- * @param path the directory path to be made.
- * @param mode
- *
- * @return 0 on successful, others on failed.
- */
-int mkdir (const char *path, mode_t mode)
-{
- int fd;
- struct dfs_fd* d;
- int result;
-
- fd = fd_new();
- if (fd == -1) { rt_kprintf("no fd\n"); return -1; }
-
- d = fd_get(fd);
-
- result = dfs_file_open(d, path, DFS_O_DIRECTORY | DFS_O_CREAT);
-
- if (result < 0)
- {
- rt_set_errno(result);
- fd_put(d);
- return -1;
- }
-
- dfs_file_close(d);
- fd_put(d);
- return 0;
-}
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-FINSH_FUNCTION_EXPORT(mkdir, create a directory);
-#endif
-
-/**
- * this function is a POSIX compliant version, which will remove a directory.
- *
- * @param pathname the path name to be removed.
- *
- * @return 0 on sucessfull, others on failed.
- */
-int rmdir(const char *pathname)
-{
- int result;
-
- result = dfs_file_unlink(pathname);
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * this function is a POSIX compliant version, which will open a directory.
- *
- * @param name the path name to be open.
- *
- * @return the DIR pointer of directory, NULL on open failed.
- */
-DIR* opendir(const char* name)
-{
- struct dfs_fd* d;
- int fd, result;
- DIR* t;
-
- t = RT_NULL;
-
- /* allocate a fd */
- fd = fd_new();
- if (fd == -1) { rt_kprintf("no fd\n"); return RT_NULL; }
- d = fd_get(fd);
-
- result = dfs_file_open(d, name, DFS_O_RDONLY | DFS_O_DIRECTORY);
- if (result >= 0)
- {
- /* open successfully */
- t = (DIR *) rt_malloc (sizeof(DIR));
- if (t == RT_NULL)
- {
- dfs_file_close(d);
- fd_put(d);
- }
- else
- {
- rt_memset(t, 0, sizeof(DIR));
- t->fd = fd;
- }
- fd_put(d);
- return t;
- }
-
- /* open failed */
- fd_put(d);
- fd_put(d);
- rt_set_errno(result);
-
- return RT_NULL;
-}
-
-/**
- * this function is a POSIX compliant version, which will return a pointer
- * to a dirent structure representing the next directory entry in the
- * directory stream.
- *
- * @param d the directory stream pointer.
- *
- * @return the next directory entry, NULL on the end of directory or failed.
- */
-struct dirent* readdir(DIR *d)
-{
- int result;
- struct dfs_fd* fd;
-
- fd = fd_get(d->fd);
- if (fd == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return RT_NULL;
- }
-
- if (!d->num || (d->cur += ((struct dirent*)(d->buf + d->cur))->d_reclen) >= d->num)
- {
- /* get a new entry */
- result = dfs_file_getdents(fd, (struct dirent*)d->buf, sizeof(d->buf) - 1);
- if (result <= 0)
- {
- rt_set_errno(result);
- fd_put(fd);
-
- return RT_NULL;
- }
-
- d->num = result;
- d->cur = 0; /* current entry index */
- }
-
- fd_put(fd);
- return (struct dirent*)(d->buf+d->cur);
-}
-
-/**
- * this function is a POSIX compliant version, which will return current
- * location in directory stream.
- *
- * @param d the directory stream pointer.
- *
- * @return the current location in directory stream.
- */
-long telldir(DIR *d)
-{
- struct dfs_fd* fd;
- long result;
-
- fd = fd_get(d->fd);
- if (fd == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return 0;
- }
-
- result = fd->pos - d->num + d->cur;
- fd_put(fd);
-
- return result;
-}
-
-/**
- * this function is a POSIX compliant version, which will set position of
- * next directory structure in the directory stream.
- *
- * @param d the directory stream.
- * @param offset the offset in directory stream.
- */
-void seekdir(DIR *d, off_t offset)
-{
- struct dfs_fd* fd;
-
- fd = fd_get(d->fd);
- if (fd == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return ;
- }
-
- /* seek to the offset position of directory */
- if (dfs_file_lseek(fd, offset) >= 0) d->num = d->cur = 0;
- fd_put(fd);
-}
-
-/**
- * this function is a POSIX compliant version, which will reset directory stream.
- *
- * @param d the directory stream.
- */
-void rewinddir(DIR *d)
-{
- struct dfs_fd* fd;
-
- fd = fd_get(d->fd);
- if (fd == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return ;
- }
-
- /* seek to the beginning of directory */
- if (dfs_file_lseek(fd, 0) >= 0) d->num = d->cur = 0;
- fd_put(fd);
-}
-
-/**
- * this function is a POSIX compliant version, which will close a directory
- * stream.
- *
- * @param d the directory stream.
- *
- * @return 0 on successful, -1 on failed.
- */
-int closedir(DIR* d)
-{
- int result;
- struct dfs_fd* fd;
-
- fd = fd_get(d->fd);
- if (fd == RT_NULL)
- {
- rt_set_errno(-RT_ERROR);
- return -1;
- }
-
- result = dfs_file_close(fd);
- fd_put(fd);
-
- fd_put(fd);
- rt_free(d);
-
- if (result < 0)
- {
- rt_set_errno(result);
- return -1;
- }
- else return 0;
-}
-
-#ifdef DFS_USING_WORKDIR
-/**
- * this function is a POSIX compliant version, which will change working directory.
- *
- * @param path the path name to be changed to.
- *
- * @return 0 on successful, -1 on failed.
- */
-int chdir(const char *path)
-{
- char* fullpath;
- DIR* d;
-
- if(path == RT_NULL)
- {
- dfs_lock();
- rt_kprintf("%s\n", working_directory);
- dfs_unlock();
- return 0;
- }
-
- if (rt_strlen(path) > DFS_PATH_MAX)
- return -1;
-
- fullpath = dfs_normalize_path(NULL, path);
- if (fullpath == RT_NULL)
- return -1; /* build path failed */
-
- dfs_lock();
- d = opendir(fullpath);
- if (d == RT_NULL)
- {
- rt_free(fullpath);
- /* this is a not exist directory */
- dfs_unlock();
- return -1;
- }
-
- /* close directory stream */
- closedir(d);
-
- /* copy full path to working directory */
- strncpy(working_directory, fullpath, DFS_PATH_MAX);
- rt_free(fullpath); /* release normalize directory path name */
-
- dfs_unlock();
-
- return 0;
-}
-#ifdef RT_USING_FINSH
-FINSH_FUNCTION_EXPORT_ALIAS(chdir, cd, change current working directory);
-#endif
-#endif
-
-/**
- * this function is a POSIX compliant version, which will return current
- * working directory.
- *
- * @param buf the returned current directory.
- * @param size the buffer size.
- *
- * @return the returned current directory.
- */
-char *getcwd(char *buf, size_t size)
-{
-#ifdef DFS_USING_WORKDIR
- rt_enter_critical();
- rt_strncpy(buf, working_directory, size);
- rt_exit_critical();
-#else
- rt_kprintf("WARNING: not support working directory\n");
-#endif
- return buf;
-}
-
-/* @} */
+/*
+ * File : dfs_posix.c
+ * This file is part of Device File System in RT-Thread RTOS
+ * COPYRIGHT (C) 2004-2010, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2009-05-27 Yi.qiu The first version
+ */
+
+#include <dfs.h>
+#include <dfs_posix.h>
+
+/**
+ * @addtogroup FsPosixApi
+ */
+/*@{*/
+
+/**
+ * this function is a POSIX compliant version, which will open a file and return
+ * a file descriptor.
+ *
+ * @param file the path name of file.
+ * @param flags the file open flags.
+ * @param mode
+ *
+ * @return the non-negative integer on successful open, others for failed.
+ */
+int open(const char *file, int flags, int mode)
+{
+ int fd, result;
+ struct dfs_fd* d;
+
+ /* allocate a fd */
+ fd = fd_new();
+ if (fd < 0) return -1;
+ d = fd_get(fd);
+
+ result = dfs_file_open(d, file, flags);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+
+ /* release the ref-count of fd */
+ fd_put(d);
+ fd_put(d);
+
+ return -1;
+ }
+
+ /* release the ref-count of fd */
+ fd_put(d);
+ return fd;
+}
+
+/**
+ * this function is a POSIX compliant version, which will close the open
+ * file descriptor.
+ *
+ * @param fd the file descriptor.
+ *
+ * @return 0 on successful, -1 on failed.
+ */
+int close(int fd)
+{
+ int result;
+ struct dfs_fd* d;
+
+ d = fd_get(fd);
+ if (d == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ result = dfs_file_close(d);
+ fd_put(d);
+
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+
+ fd_put(d);
+ return 0;
+}
+
+/**
+ * this function is a POSIX compliant version, which will read specified data buffer
+ * length for an open file descriptor.
+ *
+ * @param fd the file descriptor.
+ * @param buf the buffer to save the read data.
+ * @param len the maximal length of data buffer
+ *
+ * @return the actual read data buffer length
+ */
+int read(int fd, void *buf, size_t len)
+{
+ int result;
+ struct dfs_fd* d;
+
+ /* get the fd */
+ d = fd_get(fd);
+ if (d == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ result = dfs_file_read(d, buf, len);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ fd_put(d);
+
+ return -1;
+ }
+
+ /* release the ref-count of fd */
+ fd_put(d);
+ return result;
+}
+
+/**
+ * this function is a POSIX compliant version, which will write pecified data buffer
+ * length for an open file descriptor.
+ *
+ * @param fd the file descriptor
+ * @param buf the data buffer to be written.
+ * @param len the data buffer length.
+ *
+ * @return the actual written data buffer length.
+ */
+int write(int fd, const void *buf, size_t len)
+{
+ int result;
+ struct dfs_fd* d;
+
+ /* get the fd */
+ d = fd_get(fd);
+ if (d == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ result = dfs_file_write(d, buf, len);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ fd_put(d);
+
+ return -1;
+ }
+
+ /* release the ref-count of fd */
+ fd_put(d);
+ return result;
+}
+
+/**
+ * this function is a POSIX compliant version, which will seek the offset for an
+ * open file descriptor.
+ *
+ * @param fd the file descriptor.
+ * @param offset the offset to be seeked.
+ * @param whence the directory of seek.
+ *
+ * @return the current file position, or -1 on failed.
+ */
+off_t lseek(int fd, off_t offset, int whence)
+{
+ int result;
+ struct dfs_fd* d;
+
+ d = fd_get(fd);
+ if (d == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ switch (whence)
+ {
+ case DFS_SEEK_SET:
+ break;
+
+ case DFS_SEEK_CUR:
+ offset += d->pos;
+ break;
+
+ case DFS_SEEK_END:
+ offset += d->size;
+ break;
+ }
+
+ if( offset < 0 )
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+ result = dfs_file_lseek(d, offset);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ fd_put(d);
+ return -1;
+ }
+
+ /* release the ref-count of fd */
+ fd_put(d);
+ return offset;
+}
+
+/**
+ * this function is a POSIX compliant version, which will rename old file name to
+ * new file name.
+ *
+ * @param old the old file name.
+ * @param new the new file name.
+ *
+ * @return 0 on successful, -1 on failed.
+ *
+ * note: the old and new file name must be belong to a same file system.
+ */
+int rename(const char* old, const char* new)
+{
+ int result;
+
+ result = dfs_file_rename(old, new);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * this function is a POSIX compliant version, which will unlink (remove) a
+ * specified path file from file system.
+ *
+ * @param pathname the specified path name to be unlinked.
+ *
+ * @return 0 on successful, -1 on failed.
+ */
+int unlink(const char *pathname)
+{
+ int result;
+
+ result = dfs_file_unlink(pathname);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * this function is a POSIX compliant version, which will get file information.
+ *
+ * @param file the file name
+ * @param buf the data buffer to save stat description.
+ *
+ * @return 0 on successful, -1 on failed.
+ */
+int stat(const char *file, struct stat *buf)
+{
+ int result;
+
+ result = dfs_file_stat(file, buf);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+ return result;
+}
+
+/**
+ * this function is a POSIX compliant version, which will get file status.
+ *
+ * @param fildes the file description
+ * @param buf the data buffer to save stat description.
+ */
+int fstat(int fildes, struct stat *buf)
+{
+ struct dfs_fd* d;
+
+ /* get the fd */
+ d = fd_get(fildes);
+ if (d == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ /* it's the root directory */
+ buf->st_dev = 0;
+
+ buf->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
+ DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
+ if (d->type == FT_DIRECTORY)
+ {
+ buf->st_mode &= ~DFS_S_IFREG;
+ buf->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
+ }
+
+ buf->st_size = d->size;
+ buf->st_mtime = 0;
+ buf->st_blksize = 512;
+
+ fd_put(d);
+
+ return DFS_STATUS_OK;
+}
+
+/**
+ * this function is a POSIX compliant version, which will return the
+ * information about a mounted file system.
+ *
+ * @param path the path which mounted file system.
+ * @param buf the buffer to save the returned information.
+ *
+ * @return 0 on successful, others on failed.
+ */
+int statfs(const char *path, struct statfs *buf)
+{
+ int result;
+
+ result = dfs_statfs(path, buf);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+
+ return result;
+}
+
+/**
+ * this function is a POSIX compliant version, which will make a directory
+ *
+ * @param path the directory path to be made.
+ * @param mode
+ *
+ * @return 0 on successful, others on failed.
+ */
+int mkdir (const char *path, mode_t mode)
+{
+ int fd;
+ struct dfs_fd* d;
+ int result;
+
+ fd = fd_new();
+ if (fd == -1) { rt_kprintf("no fd\n"); return -1; }
+
+ d = fd_get(fd);
+
+ result = dfs_file_open(d, path, DFS_O_DIRECTORY | DFS_O_CREAT);
+
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ fd_put(d);
+ return -1;
+ }
+
+ dfs_file_close(d);
+ fd_put(d);
+ return 0;
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(mkdir, create a directory);
+#endif
+
+/**
+ * this function is a POSIX compliant version, which will remove a directory.
+ *
+ * @param pathname the path name to be removed.
+ *
+ * @return 0 on sucessfull, others on failed.
+ */
+int rmdir(const char *pathname)
+{
+ int result;
+
+ result = dfs_file_unlink(pathname);
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * this function is a POSIX compliant version, which will open a directory.
+ *
+ * @param name the path name to be open.
+ *
+ * @return the DIR pointer of directory, NULL on open failed.
+ */
+DIR* opendir(const char* name)
+{
+ struct dfs_fd* d;
+ int fd, result;
+ DIR* t;
+
+ t = RT_NULL;
+
+ /* allocate a fd */
+ fd = fd_new();
+ if (fd == -1) { rt_kprintf("no fd\n"); return RT_NULL; }
+ d = fd_get(fd);
+
+ result = dfs_file_open(d, name, DFS_O_RDONLY | DFS_O_DIRECTORY);
+ if (result >= 0)
+ {
+ /* open successfully */
+ t = (DIR *) rt_malloc (sizeof(DIR));
+ if (t == RT_NULL)
+ {
+ dfs_file_close(d);
+ fd_put(d);
+ }
+ else
+ {
+ rt_memset(t, 0, sizeof(DIR));
+ t->fd = fd;
+ }
+ fd_put(d);
+ return t;
+ }
+
+ /* open failed */
+ fd_put(d);
+ fd_put(d);
+ rt_set_errno(result);
+
+ return RT_NULL;
+}
+
+/**
+ * this function is a POSIX compliant version, which will return a pointer
+ * to a dirent structure representing the next directory entry in the
+ * directory stream.
+ *
+ * @param d the directory stream pointer.
+ *
+ * @return the next directory entry, NULL on the end of directory or failed.
+ */
+struct dirent* readdir(DIR *d)
+{
+ int result;
+ struct dfs_fd* fd;
+
+ fd = fd_get(d->fd);
+ if (fd == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return RT_NULL;
+ }
+
+ if (!d->num || (d->cur += ((struct dirent*)(d->buf + d->cur))->d_reclen) >= d->num)
+ {
+ /* get a new entry */
+ result = dfs_file_getdents(fd, (struct dirent*)d->buf, sizeof(d->buf) - 1);
+ if (result <= 0)
+ {
+ rt_set_errno(result);
+ fd_put(fd);
+
+ return RT_NULL;
+ }
+
+ d->num = result;
+ d->cur = 0; /* current entry index */
+ }
+
+ fd_put(fd);
+ return (struct dirent*)(d->buf+d->cur);
+}
+
+/**
+ * this function is a POSIX compliant version, which will return current
+ * location in directory stream.
+ *
+ * @param d the directory stream pointer.
+ *
+ * @return the current location in directory stream.
+ */
+long telldir(DIR *d)
+{
+ struct dfs_fd* fd;
+ long result;
+
+ fd = fd_get(d->fd);
+ if (fd == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return 0;
+ }
+
+ result = fd->pos - d->num + d->cur;
+ fd_put(fd);
+
+ return result;
+}
+
+/**
+ * this function is a POSIX compliant version, which will set position of
+ * next directory structure in the directory stream.
+ *
+ * @param d the directory stream.
+ * @param offset the offset in directory stream.
+ */
+void seekdir(DIR *d, off_t offset)
+{
+ struct dfs_fd* fd;
+
+ fd = fd_get(d->fd);
+ if (fd == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return ;
+ }
+
+ /* seek to the offset position of directory */
+ if (dfs_file_lseek(fd, offset) >= 0) d->num = d->cur = 0;
+ fd_put(fd);
+}
+
+/**
+ * this function is a POSIX compliant version, which will reset directory stream.
+ *
+ * @param d the directory stream.
+ */
+void rewinddir(DIR *d)
+{
+ struct dfs_fd* fd;
+
+ fd = fd_get(d->fd);
+ if (fd == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return ;
+ }
+
+ /* seek to the beginning of directory */
+ if (dfs_file_lseek(fd, 0) >= 0) d->num = d->cur = 0;
+ fd_put(fd);
+}
+
+/**
+ * this function is a POSIX compliant version, which will close a directory
+ * stream.
+ *
+ * @param d the directory stream.
+ *
+ * @return 0 on successful, -1 on failed.
+ */
+int closedir(DIR* d)
+{
+ int result;
+ struct dfs_fd* fd;
+
+ fd = fd_get(d->fd);
+ if (fd == RT_NULL)
+ {
+ rt_set_errno(-RT_ERROR);
+ return -1;
+ }
+
+ result = dfs_file_close(fd);
+ fd_put(fd);
+
+ fd_put(fd);
+ rt_free(d);
+
+ if (result < 0)
+ {
+ rt_set_errno(result);
+ return -1;
+ }
+ else return 0;
+}
+
+#ifdef DFS_USING_WORKDIR
+/**
+ * this function is a POSIX compliant version, which will change working directory.
+ *
+ * @param path the path name to be changed to.
+ *
+ * @return 0 on successful, -1 on failed.
+ */
+int chdir(const char *path)
+{
+ char* fullpath;
+ DIR* d;
+
+ if(path == RT_NULL)
+ {
+ dfs_lock();
+ rt_kprintf("%s\n", working_directory);
+ dfs_unlock();
+ return 0;
+ }
+
+ if (rt_strlen(path) > DFS_PATH_MAX)
+ return -1;
+
+ fullpath = dfs_normalize_path(NULL, path);
+ if (fullpath == RT_NULL)
+ return -1; /* build path failed */
+
+ dfs_lock();
+ d = opendir(fullpath);
+ if (d == RT_NULL)
+ {
+ rt_free(fullpath);
+ /* this is a not exist directory */
+ dfs_unlock();
+ return -1;
+ }
+
+ /* close directory stream */
+ closedir(d);
+
+ /* copy full path to working directory */
+ strncpy(working_directory, fullpath, DFS_PATH_MAX);
+ rt_free(fullpath); /* release normalize directory path name */
+
+ dfs_unlock();
+
+ return 0;
+}
+#ifdef RT_USING_FINSH
+FINSH_FUNCTION_EXPORT_ALIAS(chdir, cd, change current working directory);
+#endif
+#endif
+
+/**
+ * this function is a POSIX compliant version, which will return current
+ * working directory.
+ *
+ * @param buf the returned current directory.
+ * @param size the buffer size.
+ *
+ * @return the returned current directory.
+ */
+char *getcwd(char *buf, size_t size)
+{
+#ifdef DFS_USING_WORKDIR
+ rt_enter_critical();
+ rt_strncpy(buf, working_directory, size);
+ rt_exit_critical();
+#else
+ rt_kprintf("WARNING: not support working directory\n");
+#endif
+ return buf;
+}
+
+/* @} */