From 2a261eeebfdab27d0648c38ae46ff4dee3e2b0f4 Mon Sep 17 00:00:00 2001 From: Davee Date: Tue, 6 Sep 2016 20:57:40 +0100 Subject: [PATCH] implemented dirent.h functionality --- newlib/libc/sys/vita/Makefile.am | 8 +- newlib/libc/sys/vita/Makefile.in | 19 ++- newlib/libc/sys/vita/dirent.c | 247 ++++++++++++++++++++++++++++++ newlib/libc/sys/vita/sys/dirent.h | 55 +++++++ 4 files changed, 323 insertions(+), 6 deletions(-) create mode 100644 newlib/libc/sys/vita/dirent.c create mode 100644 newlib/libc/sys/vita/sys/dirent.h diff --git a/newlib/libc/sys/vita/Makefile.am b/newlib/libc/sys/vita/Makefile.am index 94a5a6acd0..54f1c0a8f0 100755 --- a/newlib/libc/sys/vita/Makefile.am +++ b/newlib/libc/sys/vita/Makefile.am @@ -9,9 +9,10 @@ AM_CCASFLAGS = $(INCLUDES) noinst_LIBRARIES = lib.a SOCKET_OBJS = accept.o bind.o connect.o getpeername.o getsockname.o getsockopt.o listen.o recv.o recvfrom.o recvmsg.o send.o sendto.o sendmsg.o setsockopt.o shutdown.o socket.o +DIRENT_OBJS = closedir.o opendir.o readdir.o readdir_r.o rewinddir.o seekdir.o telldir.o -lib_a_SOURCES = syscalls.c sbrk.c threading.c mlock.c io.c socket.c -lib_a_LIBADD = ${SOCKET_OBJS} +lib_a_SOURCES = syscalls.c sbrk.c threading.c mlock.c io.c socket.c dirent.c +lib_a_LIBADD = ${SOCKET_OBJS} ${DIRENT_OBJS} lib_a_CCASFLAGS = $(AM_CCASFLAGS) lib_a_CFLAGS = $(AM_CFLAGS) @@ -20,5 +21,8 @@ all-local: crt0.o $(SOCKET_OBJS): socket.c $(COMPILE) -DF_$* $< -c -o $@ +$(DIRENT_OBJS): dirent.c + $(COMPILE) -DF_$* $< -c -o $@ + ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host diff --git a/newlib/libc/sys/vita/Makefile.in b/newlib/libc/sys/vita/Makefile.in index bd19696ceb..ce801542cf 100644 --- a/newlib/libc/sys/vita/Makefile.in +++ b/newlib/libc/sys/vita/Makefile.in @@ -68,10 +68,11 @@ CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru lib_a_AR = $(AR) $(ARFLAGS) -lib_a_DEPENDENCIES = $(SOCKET_OBJS) +lib_a_DEPENDENCIES = $(SOCKET_OBJS) $(DIRENT_OBJS) am_lib_a_OBJECTS = lib_a-syscalls.$(OBJEXT) lib_a-sbrk.$(OBJEXT) \ lib_a-threading.$(OBJEXT) lib_a-mlock.$(OBJEXT) \ - lib_a-io.$(OBJEXT) lib_a-socket.$(OBJEXT) + lib_a-io.$(OBJEXT) lib_a-socket.$(OBJEXT) \ + lib_a-dirent.$(OBJEXT) lib_a_OBJECTS = $(am_lib_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = @@ -197,8 +198,9 @@ INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) AM_CCASFLAGS = $(INCLUDES) noinst_LIBRARIES = lib.a SOCKET_OBJS = accept.o bind.o connect.o getpeername.o getsockname.o getsockopt.o listen.o recv.o recvfrom.o recvmsg.o send.o sendto.o sendmsg.o setsockopt.o shutdown.o socket.o -lib_a_SOURCES = syscalls.c sbrk.c threading.c mlock.c io.c socket.c -lib_a_LIBADD = ${SOCKET_OBJS} +DIRENT_OBJS = closedir.o opendir.o readdir.o readdir_r.o rewinddir.o seekdir.o telldir.o +lib_a_SOURCES = syscalls.c sbrk.c threading.c mlock.c io.c socket.c dirent.c +lib_a_LIBADD = ${SOCKET_OBJS} ${DIRENT_OBJS} lib_a_CCASFLAGS = $(AM_CCASFLAGS) lib_a_CFLAGS = $(AM_CFLAGS) ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. @@ -297,6 +299,12 @@ lib_a-socket.o: socket.c lib_a-socket.obj: socket.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-socket.obj `if test -f 'socket.c'; then $(CYGPATH_W) 'socket.c'; else $(CYGPATH_W) '$(srcdir)/socket.c'; fi` +lib_a-dirent.o: dirent.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dirent.o `test -f 'dirent.c' || echo '$(srcdir)/'`dirent.c + +lib_a-dirent.obj: dirent.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dirent.obj `if test -f 'dirent.c'; then $(CYGPATH_W) 'dirent.c'; else $(CYGPATH_W) '$(srcdir)/dirent.c'; fi` + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -473,6 +481,9 @@ all-local: crt0.o $(SOCKET_OBJS): socket.c $(COMPILE) -DF_$* $< -c -o $@ +$(DIRENT_OBJS): dirent.c + $(COMPILE) -DF_$* $< -c -o $@ + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/newlib/libc/sys/vita/dirent.c b/newlib/libc/sys/vita/dirent.c new file mode 100644 index 0000000000..a9c41d820a --- /dev/null +++ b/newlib/libc/sys/vita/dirent.c @@ -0,0 +1,247 @@ +/* + +Copyright (C) 2016, David "Davee" Morgan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#define SCE_ERRNO_MASK 0xFF + + +struct DIR_ +{ + SceUID uid; + struct dirent dir; + int refcount; + char *dirname; + int index; +}; + +static inline void grab_dir(DIR *dirp) +{ + __sync_add_and_fetch(&dirp->refcount, 1); +} + +static inline void drop_dir(DIR *dirp) +{ + if (__sync_add_and_fetch(&dirp->refcount, 1) == 0) + { + free(dirp->dirname); + free(dirp); + } +} + +static inline void release_drop_dir(DIR *dirp) +{ + if (__sync_add_and_fetch(&dirp->refcount, 2) == 0) + { + free(dirp->dirname); + free(dirp); + } +} + +static inline void atomic_exchange(int *obj, int desired) +{ + __sync_synchronize(); + __sync_lock_test_and_set(obj, desired); +} + +#ifdef F_closedir +int closedir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return -1; + } + + grab_dir(dirp); + + int res = sceIoDclose(dirp->uid); + + if (res < 0) + { + errno = res & SCE_ERRNO_MASK; + drop_dir(dirp); + return -1; + } + + release_drop_dir(dirp); + + errno = 0; + return 0; +} +#endif + +#if F_opendir +DIR *opendir(const char *dirname) +{ + SceUID uid = sceIoDopen(dirname); + + if (uid < 0) + { + errno = uid & SCE_ERRNO_MASK; + return NULL; + } + + DIR *dirp = calloc(1, sizeof(DIR)); + + if (!dirp) + { + sceIoDclose(uid); + errno = ENOMEM; + return NULL; + } + + dirp->refcount = 1; + dirp->uid = uid; + dirp->dirname = strdup(dirname); + dirp->index = 0; + + errno = 0; + return dirp; +} +#endif + +#ifdef F_readdir +struct dirent *readdir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return NULL; + } + + grab_dir(dirp); + + int res = sceIoDread(dirp->uid, (SceIoDirent *)&dirp->dir); + + if (res < 0) + { + errno = res & SCE_ERRNO_MASK; + drop_dir(dirp); + return NULL; + } + + if (res == 0) + { + errno = 0; + drop_dir(dirp); + return NULL; + } + + __sync_add_and_fetch(&dirp->index, 1); + + struct dirent *dir = &dirp->dir; + drop_dir(dirp); + return dir; +} +#endif +#ifdef F_readdir_r +int readdir_r(DIR *dirp, struct dirent *x, struct dirent **y) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifdef F_rewinddir +void rewinddir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return; + } + + grab_dir(dirp); + + SceUID dirfd = sceIoDopen(dirp->dirname); + + if (dirfd < 0) + { + errno = dirfd & SCE_ERRNO_MASK; + drop_dir(dirp); + return; + } + + sceIoDclose(dirp->uid); + atomic_exchange(&dirp->uid, dirfd); + atomic_exchange(&dirp->index, 0); + + drop_dir(dirp); +} +#endif + +#ifdef F_seekdir +void seekdir(DIR *dirp, long int index) +{ + if (!dirp) + { + errno = EBADF; + return; + } + + grab_dir(dirp); + + if (index < dirp->index) + rewinddir(dirp); + + if (index < dirp->index) + { + drop_dir(dirp); + return; + } + + while (index != dirp->index) + { + if (!readdir(dirp)) + { + errno = ENOENT; + drop_dir(dirp); + return; + } + } + + drop_dir(dirp); +} +#endif + +#ifdef F_telldir +long int telldir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return -1; + } + + return dirp->index; +} +#endif diff --git a/newlib/libc/sys/vita/sys/dirent.h b/newlib/libc/sys/vita/sys/dirent.h new file mode 100644 index 0000000000..00b1b43d5d --- /dev/null +++ b/newlib/libc/sys/vita/sys/dirent.h @@ -0,0 +1,55 @@ +/* + +Copyright (C) 2016, David "Davee" Morgan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef _SYS_DIRENT_H_ +#define _SYS_DIRENT_H_ + +#include +#include + +#include + +struct dirent +{ + /** File status. */ + SceIoStat d_stat; + /** File name. */ + char d_name[256]; + /** Device-specific data. */ + void *d_private; + int dummy; +}; + +struct DIR_; +typedef struct DIR_ DIR; + +int closedir(DIR *); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *, struct dirent *, struct dirent **); +void rewinddir(DIR *); +void seekdir(DIR *, long int); +long int telldir(DIR *); + +#endif /* _SYS_DIRENT_H_ */