diff options
| author | guo <[email protected]> | 2021-10-26 09:37:43 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-26 09:37:43 +0800 |
| commit | 50bb6e33d13237f71812e81a6a13ba5ba0693c8f (patch) | |
| tree | ad7924c4e07a3748b1b83fbe57d8f7231f7635a4 /components/libc/posix/src | |
| parent | c8ee4cc67dd1815d1b0ead1bcd24156da6ab87de (diff) | |
| parent | f7548b934e210ea66e2734c3c6abbddcd1605f11 (diff) | |
Merge pull request #5212 from mysterywolf/posix
[posix][dfs] move dfs_posix dfs_poll dfs_select.c to posix folder
Diffstat (limited to 'components/libc/posix/src')
| -rw-r--r-- | components/libc/posix/src/SConscript | 10 | ||||
| -rw-r--r-- | components/libc/posix/src/delay.c | 50 | ||||
| -rw-r--r-- | components/libc/posix/src/poll.c | 230 | ||||
| -rw-r--r-- | components/libc/posix/src/select.c | 180 | ||||
| -rw-r--r-- | components/libc/posix/src/unistd.c | 1044 |
5 files changed, 1514 insertions, 0 deletions
diff --git a/components/libc/posix/src/SConscript b/components/libc/posix/src/SConscript new file mode 100644 index 0000000000..5640181ac5 --- /dev/null +++ b/components/libc/posix/src/SConscript @@ -0,0 +1,10 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + +group = DefineGroup('POSIX', src, depend = ['RT_USING_POSIX']) + +Return('group') diff --git a/components/libc/posix/src/delay.c b/components/libc/posix/src/delay.c new file mode 100644 index 0000000000..1638caafbf --- /dev/null +++ b/components/libc/posix/src/delay.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-05-07 Meco Man first Version + */ +#include <rtthread.h> +#include <rthw.h> +#define DBG_TAG "POSIX.delay" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +RT_WEAK void rt_hw_us_delay(rt_uint32_t us) +{ + (void) us; + LOG_W("Please consider implementing rt_hw_us_delay() in another file."); +} + +void msleep(unsigned int msecs) +{ + rt_thread_mdelay(msecs); +} +RTM_EXPORT(msleep); + +void ssleep(unsigned int seconds) +{ + msleep(seconds * 1000); +} +RTM_EXPORT(ssleep); + +void mdelay(unsigned long msecs) +{ + rt_hw_us_delay(msecs * 1000); +} +RTM_EXPORT(mdelay); + +void udelay(unsigned long usecs) +{ + rt_hw_us_delay(usecs); +} +RTM_EXPORT(udelay); + +void ndelay(unsigned long nsecs) +{ + rt_hw_us_delay(1); +} +RTM_EXPORT(ndelay); diff --git a/components/libc/posix/src/poll.c b/components/libc/posix/src/poll.c new file mode 100644 index 0000000000..2109fb310b --- /dev/null +++ b/components/libc/posix/src/poll.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2016-12-28 Bernard first version + * 2018-03-09 Bernard Add protection for pt->triggered. + */ +#include <stdint.h> +#include <rthw.h> +#include <rtthread.h> +#include <dfs_file.h> +#include <poll.h> + +#ifdef RT_USING_POSIX + +struct rt_poll_node; + +struct rt_poll_table +{ + rt_pollreq_t req; + rt_uint32_t triggered; /* the waited thread whether triggered */ + rt_thread_t polling_thread; + struct rt_poll_node *nodes; +}; + +struct rt_poll_node +{ + struct rt_wqueue_node wqn; + struct rt_poll_table *pt; + struct rt_poll_node *next; +}; + +static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key) +{ + struct rt_poll_node *pn; + + if (key && !((rt_ubase_t)key & wait->key)) + return -1; + + pn = rt_container_of(wait, struct rt_poll_node, wqn); + pn->pt->triggered = 1; + + return __wqueue_default_wake(wait, key); +} + +static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req) +{ + struct rt_poll_table *pt; + struct rt_poll_node *node; + + node = (struct rt_poll_node *)rt_malloc(sizeof(struct rt_poll_node)); + if (node == RT_NULL) + return; + + pt = rt_container_of(req, struct rt_poll_table, req); + + node->wqn.key = req->_key; + rt_list_init(&(node->wqn.list)); + node->wqn.polling_thread = pt->polling_thread; + node->wqn.wakeup = __wqueue_pollwake; + node->next = pt->nodes; + node->pt = pt; + pt->nodes = node; + rt_wqueue_add(wq, &node->wqn); +} + +static void poll_table_init(struct rt_poll_table *pt) +{ + pt->req._proc = _poll_add; + pt->triggered = 0; + pt->nodes = RT_NULL; + pt->polling_thread = rt_thread_self(); +} + +static int poll_wait_timeout(struct rt_poll_table *pt, int msec) +{ + rt_int32_t timeout; + int ret = 0; + struct rt_thread *thread; + rt_base_t level; + + thread = pt->polling_thread; + + timeout = rt_tick_from_millisecond(msec); + + level = rt_hw_interrupt_disable(); + + if (timeout != 0 && !pt->triggered) + { + rt_thread_suspend(thread); + if (timeout > 0) + { + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + rt_hw_interrupt_enable(level); + + rt_schedule(); + + level = rt_hw_interrupt_disable(); + } + + ret = !pt->triggered; + rt_hw_interrupt_enable(level); + + return ret; +} + +static int do_pollfd(struct pollfd *pollfd, rt_pollreq_t *req) +{ + int mask = 0; + int fd; + + fd = pollfd->fd; + + if (fd >= 0) + { + struct dfs_fd *f = fd_get(fd); + mask = POLLNVAL; + + if (f) + { + mask = POLLMASK_DEFAULT; + if (f->fops->poll) + { + req->_key = pollfd->events | POLLERR | POLLHUP; + + mask = f->fops->poll(f, req); + + /* dealwith the device return error -1*/ + if (mask < 0) + { + fd_put(f); + pollfd->revents = 0; + return mask; + } + } + /* Mask out unneeded events. */ + mask &= pollfd->events | POLLERR | POLLHUP; + fd_put(f); + } + } + pollfd->revents = mask; + + return mask; +} + +static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, int msec) +{ + int num; + int istimeout = 0; + int n; + struct pollfd *pf; + int ret = 0; + + if (msec == 0) + { + pt->req._proc = RT_NULL; + istimeout = 1; + } + + while (1) + { + pf = fds; + num = 0; + + for (n = 0; n < nfds; n ++) + { + ret = do_pollfd(pf, &pt->req); + if(ret < 0) + { + /*dealwith the device return error -1 */ + pt->req._proc = RT_NULL; + return ret; + } + else if(ret > 0) + { + num ++; + pt->req._proc = RT_NULL; + } + pf ++; + } + + pt->req._proc = RT_NULL; + + if (num || istimeout) + break; + + if (poll_wait_timeout(pt, msec)) + istimeout = 1; + } + + return num; +} + +static void poll_teardown(struct rt_poll_table *pt) +{ + struct rt_poll_node *node, *next; + + next = pt->nodes; + while (next) + { + node = next; + rt_wqueue_remove(&node->wqn); + next = node->next; + rt_free(node); + } +} + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + int num; + struct rt_poll_table table; + + poll_table_init(&table); + + num = poll_do(fds, nfds, &table, timeout); + + poll_teardown(&table); + + return num; +} + +#endif diff --git a/components/libc/posix/src/select.c b/components/libc/posix/src/select.c new file mode 100644 index 0000000000..25cda0f0d1 --- /dev/null +++ b/components/libc/posix/src/select.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2016-12-28 Bernard first version + */ +#include <rtthread.h> +#include <poll.h> +#include <sys/select.h> + +#ifdef RT_USING_POSIX + +static void fdszero(fd_set *set, int nfds) +{ + fd_mask *m; + int n; + + /* + The 'sizeof(fd_set)' of the system space may differ from user space, + so the actual size of the 'fd_set' is determined here with the parameter 'nfds' + */ + m = (fd_mask *)set; + for (n = 0; n < nfds; n += (sizeof(fd_mask) * 8)) + { + rt_memset(m, 0, sizeof(fd_mask)); + m ++; + } +} + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + int fd; + int npfds; + int msec; + int ndx; + int ret; + struct pollfd *pollset = RT_NULL; + + /* How many pollfd structures do we need to allocate? */ + for (fd = 0, npfds = 0; fd < nfds; fd++) + { + /* Check if any monitor operation is requested on this fd */ + if ((readfds && FD_ISSET(fd, readfds)) || + (writefds && FD_ISSET(fd, writefds)) || + (exceptfds && FD_ISSET(fd, exceptfds))) + { + npfds++; + } + } + + /* Allocate the descriptor list for poll() */ + if (npfds > 0) + { + pollset = (struct pollfd *)rt_calloc(npfds, sizeof(struct pollfd)); + if (!pollset) + { + return -1; + } + } + + /* Initialize the descriptor list for poll() */ + for (fd = 0, ndx = 0; fd < nfds; fd++) + { + int incr = 0; + + /* The readfs set holds the set of FDs that the caller can be assured + * of reading from without blocking. Note that POLLHUP is included as + * a read-able condition. POLLHUP will be reported at the end-of-file + * or when a connection is lost. In either case, the read() can then + * be performed without blocking. + */ + + if (readfds && FD_ISSET(fd, readfds)) + { + pollset[ndx].fd = fd; + pollset[ndx].events |= POLLIN; + incr = 1; + } + + if (writefds && FD_ISSET(fd, writefds)) + { + pollset[ndx].fd = fd; + pollset[ndx].events |= POLLOUT; + incr = 1; + } + + if (exceptfds && FD_ISSET(fd, exceptfds)) + { + pollset[ndx].fd = fd; + incr = 1; + } + + ndx += incr; + } + + RT_ASSERT(ndx == npfds); + + /* Convert the timeout to milliseconds */ + if (timeout) + { + msec = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + } + else + { + msec = -1; + } + + /* Then let poll do all of the real work. */ + + ret = poll(pollset, npfds, msec); + + /* Now set up the return values */ + if (readfds) + { + fdszero(readfds, nfds); + } + + if (writefds) + { + fdszero(writefds, nfds); + } + + if (exceptfds) + { + fdszero(exceptfds, nfds); + } + + /* Convert the poll descriptor list back into selects 3 bitsets */ + + if (ret > 0) + { + ret = 0; + for (ndx = 0; ndx < npfds; ndx++) + { + /* Check for read conditions. Note that POLLHUP is included as a + * read condition. POLLHUP will be reported when no more data will + * be available (such as when a connection is lost). In either + * case, the read() can then be performed without blocking. + */ + + if (readfds) + { + if (pollset[ndx].revents & (POLLIN | POLLHUP)) + { + FD_SET(pollset[ndx].fd, readfds); + ret++; + } + } + + /* Check for write conditions */ + if (writefds) + { + if (pollset[ndx].revents & POLLOUT) + { + FD_SET(pollset[ndx].fd, writefds); + ret++; + } + } + + /* Check for exceptions */ + if (exceptfds) + { + if (pollset[ndx].revents & POLLERR) + { + FD_SET(pollset[ndx].fd, exceptfds); + ret++; + } + } + } + } + + if (pollset) rt_free(pollset); + + return ret; +} + +#endif diff --git a/components/libc/posix/src/unistd.c b/components/libc/posix/src/unistd.c new file mode 100644 index 0000000000..ef2df2c2fe --- /dev/null +++ b/components/libc/posix/src/unistd.c @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-09-01 Meco Man first Version + * 2021-02-12 Meco Man move all functions located in <pthread_sleep.c> to this file + */ +#include <rtthread.h> +#include <dfs_file.h> +#include <dfs_private.h> +#include <sys/errno.h> +#include <unistd.h> +#include <delay.h> + +/** + * this function is a POSIX compliant version, which will open a file and + * return a file descriptor according specified flags. + * + * @param file the path name of file. + * @param flags the file open flags. + * + * @return the non-negative integer on successful open, others for failed. + */ +int open(const char *file, int flags, ...) +{ + int fd, result; + struct dfs_fd *d; + + /* allocate a fd */ + fd = fd_new(); + if (fd < 0) + { + rt_set_errno(-ENOMEM); + + return -1; + } + d = fd_get(fd); + + result = dfs_file_open(d, file, flags); + if (result < 0) + { + /* release the ref-count of fd */ + fd_put(d); + fd_put(d); + + rt_set_errno(result); + + return -1; + } + + /* release the ref-count of fd */ + fd_put(d); + + return fd; +} +RTM_EXPORT(open); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + result = dfs_file_close(d); + fd_put(d); + + if (result < 0) + { + rt_set_errno(result); + + return -1; + } + + fd_put(d); + + return 0; +} +RTM_EXPORT(close); + +/** + * 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. If the returned value is 0, it + * may be reach the end of file, please check errno. + */ +#ifdef _READ_WRITE_RETURN_TYPE +_READ_WRITE_RETURN_TYPE read(int fd, void *buf, size_t len) /* some gcc tool chains will use different data structure */ +#else +ssize_t read(int fd, void *buf, size_t len) +#endif +{ + int result; + struct dfs_fd *d; + + /* get the fd */ + d = fd_get(fd); + if (d == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + result = dfs_file_read(d, buf, len); + if (result < 0) + { + fd_put(d); + rt_set_errno(result); + + return -1; + } + + /* release the ref-count of fd */ + fd_put(d); + + return result; +} +RTM_EXPORT(read); + +/** + * this function is a POSIX compliant version, which will write specified 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. + */ +#ifdef _READ_WRITE_RETURN_TYPE +_READ_WRITE_RETURN_TYPE write(int fd, const void *buf, size_t len) /* some gcc tool chains will use different data structure */ +#else +ssize_t write(int fd, const void *buf, size_t len) +#endif +{ + int result; + struct dfs_fd *d; + + /* get the fd */ + d = fd_get(fd); + if (d == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + result = dfs_file_write(d, buf, len); + if (result < 0) + { + fd_put(d); + rt_set_errno(result); + + return -1; + } + + /* release the ref-count of fd */ + fd_put(d); + + return result; +} +RTM_EXPORT(write); + +/** + * 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 read/write position in the file, 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 == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + switch (whence) + { + case SEEK_SET: + break; + + case SEEK_CUR: + offset += d->pos; + break; + + case SEEK_END: + offset += d->size; + break; + + default: + fd_put(d); + rt_set_errno(-EINVAL); + + return -1; + } + + if (offset < 0) + { + fd_put(d); + rt_set_errno(-EINVAL); + + return -1; + } + result = dfs_file_lseek(d, offset); + if (result < 0) + { + fd_put(d); + rt_set_errno(result); + + return -1; + } + + /* release the ref-count of fd */ + fd_put(d); + + return offset; +} +RTM_EXPORT(lseek); + +#ifndef _WIN32 /* we can not implement these functions */ +/** + * 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_file, const char *new_file) +{ + int result; + + result = dfs_file_rename(old_file, new_file); + if (result < 0) + { + rt_set_errno(result); + + return -1; + } + + return 0; +} +RTM_EXPORT(rename); +#endif + +/** + * 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; +} +RTM_EXPORT(unlink); + +/** + * 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; +} +RTM_EXPORT(stat); + +/** + * 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. + * + * @return 0 on successful, -1 on failed. + */ +int fstat(int fildes, struct stat *buf) +{ + struct dfs_fd *d; + + /* get the fd */ + d = fd_get(fildes); + if (d == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + /* it's the root directory */ + buf->st_dev = 0; + + buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP | S_IWOTH; + if (d->type == FT_DIRECTORY) + { + buf->st_mode &= ~S_IFREG; + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + } + + buf->st_size = d->size; + buf->st_mtime = 0; + + fd_put(d); + + return RT_EOK; +} +RTM_EXPORT(fstat); + +/** + * this function is a POSIX compliant version, which shall request that all data + * for the open file descriptor named by fildes is to be transferred to the storage + * device associated with the file described by fildes. + * + * @param fildes the file description + * + * @return 0 on successful completion. Otherwise, -1 shall be returned and errno + * set to indicate the error. + */ +int fsync(int fildes) +{ + int ret; + struct dfs_fd *d; + + /* get the fd */ + d = fd_get(fildes); + if (d == NULL) + { + rt_set_errno(-EBADF); + return -1; + } + + ret = dfs_file_flush(d); + + fd_put(d); + return ret; +} +RTM_EXPORT(fsync); + +/** + * this function is a POSIX compliant version, which shall perform a variety of + * control functions on devices. + * + * @param fildes the file description + * @param cmd the specified command + * @param data represents the additional information that is needed by this + * specific device to perform the requested function. + * + * @return 0 on successful completion. Otherwise, -1 shall be returned and errno + * set to indicate the error. + */ +int fcntl(int fildes, int cmd, ...) +{ + int ret = -1; + struct dfs_fd *d; + + /* get the fd */ + d = fd_get(fildes); + if (d) + { + void *arg; + va_list ap; + + va_start(ap, cmd); + arg = va_arg(ap, void *); + va_end(ap); + + ret = dfs_file_ioctl(d, cmd, arg); + fd_put(d); + } + else ret = -EBADF; + + if (ret < 0) + { + rt_set_errno(ret); + ret = -1; + } + + return ret; +} +RTM_EXPORT(fcntl); + +/** + * this function is a POSIX compliant version, which shall perform a variety of + * control functions on devices. + * + * @param fildes the file description + * @param cmd the specified command + * @param data represents the additional information that is needed by this + * specific device to perform the requested function. + * + * @return 0 on successful completion. Otherwise, -1 shall be returned and errno + * set to indicate the error. + */ +int ioctl(int fildes, int cmd, ...) +{ + void *arg; + va_list ap; + + va_start(ap, cmd); + arg = va_arg(ap, void *); + va_end(ap); + + /* we use fcntl for this API. */ + return fcntl(fildes, cmd, arg); +} +RTM_EXPORT(ioctl); + +/** + * + * this function is a POSIX compliant version, which cause the regular file + * referenced by fd to be truncated to a size of precisely length bytes. + * @param fd the file descriptor. + * @param length the length to be truncated. + * + * @return Upon successful completion, ftruncate() shall return 0; + * otherwise, -1 shall be returned and errno set to indicate the error. + */ +int ftruncate(int fd, off_t length) +{ + int result; + struct dfs_fd *d; + + d = fd_get(fd); + if (d == NULL) + { + rt_set_errno(-EBADF); + + return -1; + } + + if (length < 0) + { + fd_put(d); + rt_set_errno(-EINVAL); + + return -1; + } + result = dfs_file_ftruncate(d, length); + if (result < 0) + { + fd_put(d); + rt_set_errno(result); + + return -1; + } + + /* release the ref-count of fd */ + fd_put(d); + + return 0; +} +RTM_EXPORT(ftruncate); + +/** + * 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; +} +RTM_EXPORT(statfs); + +/** + * 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_set_errno(-ENOMEM); + + return -1; + } + + d = fd_get(fd); + + result = dfs_file_open(d, path, O_DIRECTORY | O_CREAT); + + if (result < 0) + { + fd_put(d); + fd_put(d); + rt_set_errno(result); + + return -1; + } + + dfs_file_close(d); + fd_put(d); + fd_put(d); + + return 0; +} +RTM_EXPORT(mkdir); + +/** + * this function is a POSIX compliant version, which will remove a directory. + * + * @param pathname the path name to be removed. + * + * @return 0 on successful, 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; +} +RTM_EXPORT(rmdir); + +/** + * 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 directory failed. + */ +DIR *opendir(const char *name) +{ + struct dfs_fd *d; + int fd, result; + DIR *t; + + t = NULL; + + /* allocate a fd */ + fd = fd_new(); + if (fd == -1) + { + rt_set_errno(-ENOMEM); + + return NULL; + } + d = fd_get(fd); + + result = dfs_file_open(d, name, O_RDONLY | O_DIRECTORY); + if (result >= 0) + { + /* open successfully */ + t = (DIR *) rt_malloc(sizeof(DIR)); + if (t == NULL) + { + dfs_file_close(d); + fd_put(d); + } + else + { + 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 NULL; +} +RTM_EXPORT(opendir); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + return NULL; + } + + if (d->num) + { + struct dirent *dirent_ptr; + dirent_ptr = (struct dirent *)&d->buf[d->cur]; + d->cur += dirent_ptr->d_reclen; + } + + if (!d->num || d->cur >= d->num) + { + /* get a new entry */ + result = dfs_file_getdents(fd, + (struct dirent *)d->buf, + sizeof(d->buf) - 1); + if (result <= 0) + { + fd_put(fd); + rt_set_errno(result); + + return NULL; + } + + d->num = result; + d->cur = 0; /* current entry index */ + } + + fd_put(fd); + + return (struct dirent *)(d->buf + d->cur); +} +RTM_EXPORT(readdir); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + + return 0; + } + + result = fd->pos - d->num + d->cur; + fd_put(fd); + + return result; +} +RTM_EXPORT(telldir); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + + return ; + } + + /* seek to the offset position of directory */ + if (dfs_file_lseek(fd, offset) >= 0) + d->num = d->cur = 0; + fd_put(fd); +} +RTM_EXPORT(seekdir); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + + return ; + } + + /* seek to the beginning of directory */ + if (dfs_file_lseek(fd, 0) >= 0) + d->num = d->cur = 0; + fd_put(fd); +} +RTM_EXPORT(rewinddir); + +/** + * 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 == NULL) + { + rt_set_errno(-EBADF); + + 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; +} +RTM_EXPORT(closedir); + +#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 == NULL) + { + dfs_lock(); + rt_kprintf("%s\n", working_directory); + dfs_unlock(); + + return 0; + } + + if (strlen(path) > DFS_PATH_MAX) + { + rt_set_errno(-ENOTDIR); + + return -1; + } + + fullpath = dfs_normalize_path(NULL, path); + if (fullpath == NULL) + { + rt_set_errno(-ENOTDIR); + + return -1; /* build path failed */ + } + + dfs_lock(); + d = opendir(fullpath); + if (d == 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); + /* release normalize directory path name */ + rt_free(fullpath); + + dfs_unlock(); + + return 0; +} +RTM_EXPORT(chdir); + +#ifdef RT_USING_FINSH +FINSH_FUNCTION_EXPORT_ALIAS(chdir, cd, change current working directory); +#endif +#endif + +/** + * this function is a POSIX compliant version, which shall check the file named + * by the pathname pointed to by the path argument for accessibility according + * to the bit pattern contained in amode. + * + * @param path the specified file/dir path. + * @param amode the value is either the bitwise-inclusive OR of the access + * permissions to be checked (R_OK, W_OK, X_OK) or the existence test (F_OK). + */ +int access(const char *path, int amode) +{ + struct stat sb; + if (stat(path, &sb) < 0) + return -1; /* already sets errno */ + + /* ignore R_OK,W_OK,X_OK condition */ + return 0; +} + +/** + * 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 + dfs_lock(); + strncpy(buf, working_directory, size); + dfs_unlock(); +#else + rt_kprintf(NO_WORKING_DIR); +#endif + + return buf; +} +RTM_EXPORT(getcwd); + +#ifdef RT_USING_POSIX_TERMIOS +#include "termios.h" +int isatty(int fd) +{ + struct termios ts; + return(tcgetattr(fd, &ts) != -1); /*true if no error (is a tty)*/ +} +#else +int isatty(int fd) +{ + if (fd >=0 && fd < 3) + { + return 1; + } + else + { + return 0; + } +} +#endif +RTM_EXPORT(isatty); + +char *ttyname(int fd) +{ + return "/dev/tty"; /* TODO: need to add more specific */ +} +RTM_EXPORT(ttyname); + +unsigned int sleep(unsigned int seconds) +{ + if (rt_thread_self() != RT_NULL) + { + ssleep(seconds); + } + else /* scheduler has not run yet */ + { + while(seconds > 0) + { + udelay(1000000u); + seconds --; + } + } + + return 0; +} +RTM_EXPORT(sleep); + +int usleep(useconds_t usec) +{ + if (rt_thread_self() != RT_NULL) + { + msleep(usec / 1000u); + } + else /* scheduler has not run yet */ + { + udelay(usec / 1000u); + } + udelay(usec % 1000u); + + return 0; +} +RTM_EXPORT(usleep); + +pid_t gettid(void) +{ + /*TODO*/ + return 0; +} + +pid_t getpid(void) +{ + return gettid(); +} +RTM_EXPORT(getpid); + +pid_t getppid(void) +{ + return 0; +} +RTM_EXPORT(getppid); + +uid_t getuid(void) +{ + return 0; /*ROOT*/ +} +RTM_EXPORT(getuid); + +uid_t geteuid(void) +{ + return 0; /*ROOT*/ +} +RTM_EXPORT(geteuid); + +gid_t getgid(void) +{ + return 0; /*ROOT*/ +} +RTM_EXPORT(getgid); + +gid_t getegid(void) +{ + return 0; /*ROOT*/ +} +RTM_EXPORT(getegid); |
