diff options
| author | [email protected] <[email protected]> | 2011-10-17 11:33:30 +0000 |
|---|---|---|
| committer | [email protected] <[email protected]> | 2011-10-17 11:33:30 +0000 |
| commit | f66dafe7a65e8203564a4fb9b4176170737e40ac (patch) | |
| tree | 9cba29297dd8cd4d91ccd5877158df0902e823e7 /components | |
| parent | 3d9e766c8641ce4b685c07fc1e6e0bfa31953469 (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.c | 1341 |
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;
+}
+
+/* @} */
|
