--- ./newlib/libc/sys/psp/libcglue.c.orig 2012-01-25 19:33:12.000000000 +0000 +++ ./newlib/libc/sys/psp/libcglue.c 2012-01-25 19:33:12.000000000 +0000 @@ -0,0 +1,969 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * libcglue.c - Newlib-compatible system calls. + * + * Copyright (c) 2005 Marcus R. Brown + * Copyright (c) 2005 James Forshaw + * Copyright (c) 2005 John Kelley + * Copyright (c) 2005 Jim Paris + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fdman.h" + +extern char __psp_cwd[MAXPATHLEN + 1]; +extern void __psp_init_cwd(char *argv_0); +extern int __psp_path_absolute(const char *in, char *out, int len); +extern int pspDisableInterrupts(); +extern void pspEnableInterrupts(int); + +/* The following functions are defined in socket.c. They have weak linkage so + that the user doesn't have to link against the PSP network libraries if they + don't use the sockets API. */ +extern int __psp_socket_close(int s) __attribute__((weak)); +extern ssize_t __psp_socket_recv(int s, void *buf, size_t len, int flags) __attribute__((weak)); +extern ssize_t __psp_socket_send(int s, const void *buf, size_t len, int flags) __attribute__((weak)); + +extern int pipe(int fildes[2]); +extern int __psp_pipe_close(int filedes); +extern int __psp_pipe_nonblocking_read(int fd, void *buf, size_t len); +extern int __psp_pipe_read(int fd, void *buf, size_t len); +extern int __psp_pipe_write(int fd, const void *buf, size_t size); +extern int __psp_pipe_nonblocking_write(int fd, const void *buf, size_t len); + +int __psp_set_errno(int code); + +#ifdef F___psp_set_errno +int __psp_set_errno(int code) +{ + if ((code & 0x80010000) == 0x80010000) { + errno = code & 0xFFFF; + return -1; + } + return code; +} +#endif + +#ifdef F_getcwd +char *getcwd(char *buf, size_t size) +{ + if(!buf) { + errno = EINVAL; + return NULL; + } + + if(strlen(__psp_cwd) >= size) { + errno = ERANGE; + return NULL; + } + + strcpy(buf, __psp_cwd); + return buf; +} +#endif + +#ifdef F_chdir +int chdir(const char *path) +{ + char dest[MAXPATHLEN + 1]; + SceUID uid; + + if(__psp_path_absolute(path, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + /* sceIoChdir doesn't give an indication of whether it worked, + so test for existence by attempting to open the dir */ + uid = sceIoDopen(dest); + if(uid < 0) { + errno = ENOTDIR; + return -1; + } + sceIoDclose(uid); + + sceIoChdir(dest); + strcpy(__psp_cwd, dest); + return 0; +} +#endif + +#ifdef F_mkdir +int mkdir(const char *pathname, mode_t mode) +{ + char dest[MAXPATHLEN + 1]; + + if(__psp_path_absolute(pathname, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __psp_set_errno(sceIoMkdir(dest, mode)); +} +#endif + +#ifdef F_rmdir +int rmdir(const char *pathname) +{ + char dest[MAXPATHLEN + 1]; + + if(__psp_path_absolute(pathname, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __psp_set_errno(sceIoRmdir(dest)); +} +#endif + +#ifdef F_realpath +char *realpath(const char *path, char *resolved_path) +{ + if(!path || !resolved_path) { + errno = EINVAL; + return NULL; + } + if(__psp_path_absolute(path, resolved_path, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return NULL; + } + if(access(resolved_path, F_OK) < 0) { + errno = ENOENT; + return NULL; + } + return resolved_path; +} +#endif + +/* Wrappers of the standard open(), close(), read(), write(), unlink() and lseek() routines. */ +#ifdef F__open +int _open(const char *name, int flags, int mode) +{ + int scefd, fd; + int sce_flags; + char dest[MAXPATHLEN + 1]; + + if(__psp_path_absolute(name, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + /* O_RDONLY starts at 0, where PSP_O_RDONLY starts at 1, so remap the read/write + flags by adding 1. */ + sce_flags = (flags & O_ACCMODE) + 1; + + /* Translate standard open flags into the flags understood by the PSP kernel. */ + if (flags & O_APPEND) { + sce_flags |= PSP_O_APPEND; + } + if (flags & O_CREAT) { + sce_flags |= PSP_O_CREAT; + } + if (flags & O_TRUNC) { + sce_flags |= PSP_O_TRUNC; + } + if (flags & O_EXCL) { + sce_flags |= PSP_O_EXCL; + } + if (flags & O_NONBLOCK) { + sce_flags |= PSP_O_NBLOCK; + } + + scefd = sceIoOpen(dest, sce_flags, mode); + if (scefd >= 0) { + fd = __psp_fdman_get_new_descriptor(); + if (fd != -1) { + __psp_descriptormap[fd]->sce_descriptor = scefd; + __psp_descriptormap[fd]->type = __PSP_DESCRIPTOR_TYPE_FILE; + __psp_descriptormap[fd]->flags = flags; + __psp_descriptormap[fd]->filename = strdup(dest); + return fd; + } + else { + sceIoClose(scefd); + errno = ENOMEM; + return -1; + } + } + else { + return __psp_set_errno(scefd); + } + +} +#endif + +#ifdef F__close +int _close(int fd) +{ + int ret = 0; + + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_FILE: + case __PSP_DESCRIPTOR_TYPE_TTY: + if (__psp_descriptormap[fd]->ref_count == 1) { + ret = __psp_set_errno(sceIoClose(__psp_descriptormap[fd]->sce_descriptor)); + } + __psp_fdman_release_descriptor(fd); + return ret; + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + return __psp_pipe_close(fd); + break; + case __PSP_DESCRIPTOR_TYPE_SOCKET: + if (__psp_socket_close != NULL) { + ret = __psp_socket_close(fd); + return ret; + } + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F__read +int _read(int fd, void *buf, size_t size) +{ + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_FILE: + case __PSP_DESCRIPTOR_TYPE_TTY: + return __psp_set_errno(sceIoRead(__psp_descriptormap[fd]->sce_descriptor, buf, size)); + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + if (__psp_descriptormap[fd]->flags & O_NONBLOCK) { + return __psp_pipe_nonblocking_read(fd, buf, size); + } + else { + return __psp_pipe_read(fd, buf, size); + } + break; + case __PSP_DESCRIPTOR_TYPE_SOCKET: + if (__psp_socket_recv != NULL) { + return __psp_socket_recv(fd, buf, size, 0); + } + break; + default: + break; + } + + errno = EBADF; + return -1; + +} +#endif + +#ifdef F__write +int _write(int fd, const void *buf, size_t size) +{ + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_FILE: + case __PSP_DESCRIPTOR_TYPE_TTY: + return __psp_set_errno(sceIoWrite(__psp_descriptormap[fd]->sce_descriptor, buf, size)); + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + if (__psp_descriptormap[fd]->flags & O_NONBLOCK) { + return __psp_pipe_nonblocking_write(fd, buf, size); + } + else { + return __psp_pipe_write(fd, buf, size); + } + break; + break; + case __PSP_DESCRIPTOR_TYPE_SOCKET: + if (__psp_socket_send != NULL) { + return __psp_socket_send(fd, buf, size, 0); + } + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F__lseek +off_t _lseek(int fd, off_t offset, int whence) +{ + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_FILE: + /* We don't have to do anything with the whence argument because SEEK_* == PSP_SEEK_*. */ + return (off_t) __psp_set_errno(sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, offset, whence)); + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + break; + case __PSP_DESCRIPTOR_TYPE_SOCKET: + break; + default: + break; + } + + errno = EBADF; + return -1; + +} +#endif + +#ifdef F__unlink +int _unlink(const char *path) +{ + char dest[MAXPATHLEN + 1]; + + if(__psp_path_absolute(path, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __psp_set_errno(sceIoRemove(dest)); +} +#endif + +#ifdef F__link +int _link(const char *name1, const char *name2) +{ + errno = ENOSYS; + return -1; /* not supported */ +} +#endif + +#ifdef F_opendir +DIR *opendir(const char *filename) +{ + char dest[MAXPATHLEN + 1]; + DIR *dirp; + SceUID uid; + + /* Normalize pathname so that opendir(".") works */ + if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) { + errno = ENOENT; + return NULL; + } + + dirp = (DIR *)malloc(sizeof(DIR)); + + uid = sceIoDopen(dest); + + if (uid < 0) + { + free(dirp); + (void) __psp_set_errno(uid); + return NULL; + } + + dirp->uid = uid; + + return dirp; +} +#endif + +#ifdef F_readdir +struct dirent *readdir(DIR *dirp) +{ + int ret; + + /* Zero the dirent, to avoid possible problems with sceIoDread */ + memset(&dirp->de, 0, sizeof(struct dirent)); + + ret = sceIoDread(dirp->uid, (SceIoDirent *)&dirp->de); + if (ret == 0) { + /* EOF */ + errno = 0; + return NULL; + } + if (ret < 0) { + (void) __psp_set_errno(ret); + return NULL; + } + + return &dirp->de; +} +#endif + +#ifdef F_closedir +int closedir(DIR *dirp) +{ + if (dirp != NULL) + { + int uid; + uid = dirp->uid; + free (dirp); + return __psp_set_errno(sceIoDclose(uid)); + } + errno = EBADF; + return -1; +} +#endif + +/* Time routines. These wrap around the routines provided by the kernel. */ +#ifdef F__gettimeofday +int _gettimeofday(struct timeval *tp, struct timezone *tzp) +{ + int ret; + time_t t; + struct timeval tv1, tv2; + + /* The kernel sceKernelLibcGettimeofday only returns time + since midnight. To get a proper timeval return value, we + get seconds using sceKernelLibcTime and microseconds using + sceKernelLibcGettimeofday. Since we are reading the time + with two different function calls, we need to be careful + to avoid glitches when the time changes between calls. */ + + retry: + /* Get seconds and microseconds since midnight */ + ret = __psp_set_errno(sceKernelLibcGettimeofday(&tv1, tzp)); + if (ret < 0) + return ret; + + /* Get seconds since epoch */ + ret = __psp_set_errno(sceKernelLibcTime(&t)); + if (ret < 0) + return ret; + + /* Get seconds and microseconds since midnight, again */ + ret = __psp_set_errno(sceKernelLibcGettimeofday(&tv2, tzp)); + if (ret < 0) + return ret; + + /* Retry if microseconds wrapped around */ + if (tv2.tv_usec < tv1.tv_usec) + goto retry; + + /* Return the actual time since epoch */ + tp->tv_sec = t; + tp->tv_usec = tv2.tv_usec; + + return 0; +} + +#endif + +#if defined(F_clock) +clock_t clock(void) +{ + return sceKernelLibcClock(); +} +#endif + +#if defined(F_time) +time_t time(time_t *t) +{ + return __psp_set_errno(sceKernelLibcTime(t)); +} +#endif + +#if defined(F_sleep) +unsigned int sleep(unsigned int secs) { + while(secs--) { + sceKernelDelayThreadCB(1000000); + } + return 0; +} +#endif + +/* PSP-compatible sbrk(). */ +#if defined(F__sbrk) || defined(F_glue__sbrk) + +#define DEFAULT_PRX_HEAP_SIZE_KB 64 + +/* If defined it specifies the desired size of the heap, in KB. */ +extern int sce_newlib_heap_kb_size __attribute__((weak)); +extern int __pspsdk_is_prx __attribute__((weak)); + +/* UID of the memory block that represents the heap. */ +static SceUID __psp_heap_blockid; + +void * _sbrk(ptrdiff_t incr) +{ + static void * heap_bottom = NULL; + static void * heap_top = NULL; + static void * heap_ptr = NULL; + + /* Has our heap been initialized? */ + if (heap_bottom == NULL) { + /* No, initialize the heap. */ + SceSize heap_size = (SceSize) -1; + + if (&sce_newlib_heap_kb_size != NULL) { + heap_size = sce_newlib_heap_kb_size; + } else if(&__pspsdk_is_prx != NULL) { + heap_size = DEFAULT_PRX_HEAP_SIZE_KB; + } + + heap_size *= 1024; + if ((int)heap_size < 0) { + heap_size += sceKernelMaxFreeMemSize(); + } + + if (heap_size != 0) { + __psp_heap_blockid = sceKernelAllocPartitionMemory(2, "block", PSP_SMEM_Low, heap_size, NULL); + if (__psp_heap_blockid > 0) { + heap_bottom = sceKernelGetBlockHeadAddr(__psp_heap_blockid); + heap_ptr = heap_bottom; + heap_top = (unsigned char *) heap_bottom + heap_size; + } + } + } + + void * heap_addr = (void *) -1; + void * next_heap_ptr = (void *) ((ptrdiff_t) heap_ptr + incr); + if ((heap_bottom != NULL) && (next_heap_ptr >= heap_bottom) && (next_heap_ptr < heap_top)) { + heap_addr = heap_ptr; + heap_ptr = next_heap_ptr; + } + + return heap_addr; +} + +/* Free the heap. */ +int __psp_free_heap(void) +{ + if (__psp_heap_blockid > 0) { + return sceKernelFreePartitionMemory(__psp_heap_blockid); + } + + return __psp_heap_blockid; +} +#endif + +/* Other POSIX routines that must be defined. */ +#ifdef F__fstat +int _fstat(int fd, struct stat *sbuf) +{ + int ret; + SceOff oldpos; + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_TTY: + memset(sbuf, '\0', sizeof(struct stat)); + sbuf->st_mode = S_IFCHR; + return 0; + break; + case __PSP_DESCRIPTOR_TYPE_FILE: + if (__psp_descriptormap[fd]->filename != NULL) { + ret = stat(__psp_descriptormap[fd]->filename, sbuf); + + /* Find true size of the open file */ + oldpos = sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, 0, SEEK_CUR); + if (oldpos != (off_t) -1) { + sbuf->st_size = (off_t) sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, 0, SEEK_END); + sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, oldpos, SEEK_SET); + } + return ret; + } + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + case __PSP_DESCRIPTOR_TYPE_SOCKET: + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F_isatty +int isatty(int fd) +{ + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return 0; + } + + if (__psp_descriptormap[fd]->type == __PSP_DESCRIPTOR_TYPE_TTY) { + return 1; + } + else { + return 0; + } +} +#endif + +#ifdef F__isatty +int _isatty(int fd) +{ + return isatty(fd); +} +#endif + +#ifdef F__stat +static time_t psp_to_epoch_time(ScePspDateTime psp_time) +{ + struct tm conv_time; + conv_time.tm_year = psp_time.year; + conv_time.tm_mon = psp_time.month; + conv_time.tm_mday = psp_time.day; + conv_time.tm_hour = psp_time.hour; + conv_time.tm_min = psp_time.minute; + conv_time.tm_sec = psp_time.second; + conv_time.tm_isdst = -1; + return mktime(&conv_time); +} + +int _stat(const char *filename, struct stat *buf) +{ + SceIoStat psp_stat; + char dest[MAXPATHLEN + 1]; + int ret; + + if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + memset(buf, '\0', sizeof(struct stat)); + ret = sceIoGetstat(dest, &psp_stat); + if (ret < 0) { + return __psp_set_errno(ret); + } + + buf->st_ctime = psp_to_epoch_time(psp_stat.st_ctime); + buf->st_atime = psp_to_epoch_time(psp_stat.st_atime); + buf->st_mtime = psp_to_epoch_time(psp_stat.st_mtime); + + buf->st_mode = (psp_stat.st_mode & 0xfff) | + ((FIO_S_ISLNK(psp_stat.st_mode))?(S_IFLNK):(0)) | + ((FIO_S_ISREG(psp_stat.st_mode))?(S_IFREG):(0)) | + ((FIO_S_ISDIR(psp_stat.st_mode))?(S_IFDIR):(0)); + buf->st_size = psp_stat.st_size; + return 0; +} +#endif + +/* from stat.h in ps2sdk, this function may be correct */ +#define FIO_CST_SIZE 0x0004 + +#ifdef F_truncate +int truncate(const char *filename, off_t length) +{ + SceIoStat psp_stat; + char dest[MAXPATHLEN + 1]; + + if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + psp_stat.st_size = length; + if(length < 0) + { + errno = EINVAL; + return -1; + } + return __psp_set_errno(sceIoChstat(dest, &psp_stat, FIO_CST_SIZE)); +} +#endif + +/* Unsupported newlib system calls. */ +#ifdef F__fork +pid_t fork(void) +{ + errno = ENOSYS; + return (pid_t) -1; +} +#endif + +#ifdef F__getpid +pid_t _getpid(void) +{ + errno = ENOSYS; + return (pid_t) -1; +} +#endif + +#ifdef F__kill +int _kill(int unused, int unused2) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifdef F__wait +pid_t _wait(int *unused) +{ + errno = ENOSYS; + return (pid_t) -1; +} +#endif + +#ifdef F_access +int access(const char *fn, int flags) +{ + struct stat s; + if (stat(fn, &s)) + return -1; + if (s.st_mode & S_IFDIR) + return 0; + if (flags & W_OK) + { + if (s.st_mode & S_IWRITE) + return 0; + errno = EACCES; + return -1; + } + return 0; +} +#endif + +#ifdef F__fcntl +int _fcntl(int fd, int cmd, ...) +{ + if (!__PSP_IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch (cmd) + { + case F_DUPFD: + { + return __psp_fdman_get_dup_descriptor(fd); + break; + } + case F_GETFL: + { + return __psp_descriptormap[fd]->flags; + break; + } + case F_SETFL: + { + int newfl; + va_list args; + + va_start (args, cmd); /* Initialize the argument list. */ + newfl = va_arg(args, int); + va_end (args); /* Clean up. */ + + __psp_descriptormap[fd]->flags = newfl; + + switch(__psp_descriptormap[fd]->type) + { + case __PSP_DESCRIPTOR_TYPE_FILE: + break; + case __PSP_DESCRIPTOR_TYPE_PIPE: + break; + case __PSP_DESCRIPTOR_TYPE_SOCKET: + if (newfl & O_NONBLOCK) + { + int one = 1; + return setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, (char *)&one, sizeof(one)); + } + else + { + int zero = 0; + return setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, (char *)&zero, sizeof(zero)); + } + break; + default: + break; + } + return 0; + break; + } + } + + errno = EBADF; + return -1; +} +#endif /* F__fcntl */ + +#ifdef F_tzset +void tzset(void) +{ + static int initialized = 0; + + if (!initialized) + { + initialized = 1; + + /* Don't init if TZ has already been set once, this probably means the user + wanted to override what we would set below. */ + if (getenv("TZ") == NULL) + { + /* Initialize timezone from PSP configuration */ + int tzOffset = 0; + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_TIMEZONE, &tzOffset); + int tzOffsetAbs = tzOffset < 0 ? -tzOffset : tzOffset; + int hours = tzOffsetAbs / 60; + int minutes = tzOffsetAbs - hours * 60; + int pspDaylight = 0; + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS, &pspDaylight); + static char tz[18]; + sprintf(tz, "GMT%s%02i:%02i%s", tzOffset < 0 ? "+" : "-", hours, minutes, pspDaylight ? "daylight" : ""); + setenv("TZ", tz, 1); + } + } + + _tzset_r(_REENT); +} +#endif + +#ifdef F_mlock +static unsigned int lock_count = 0; +static unsigned int intr_flags = 0; + +void __malloc_lock(struct _reent *ptr) +{ + unsigned int flags = pspDisableInterrupts(); + + if (lock_count == 0) { + intr_flags = flags; + } + + lock_count++; +} + +void __malloc_unlock(struct _reent *ptr) +{ + if (--lock_count == 0) { + pspEnableInterrupts(intr_flags); + } +} +#endif + +/* Exit. */ +#if defined(F__exit) || defined(F_glue__exit) +extern int sce_newlib_nocreate_thread_in_start __attribute__((weak)); + +extern int __psp_free_heap(void); + +void _exit(int status) +{ + if (&sce_newlib_nocreate_thread_in_start == NULL) { + /* Free the heap created by _sbrk(). */ + __psp_free_heap(); + + sceKernelSelfStopUnloadModule(1, 0, NULL); + } else { + if (status == 0) { + /* Free the heap created by _sbrk(). */ + __psp_free_heap(); + } + + sceKernelExitThread(status); + } + + while (1) ; +} + +/* Note: This function is being linked into _exit.o. + + Because __psp_libc_init is a weak import in crt0.c, the linker + chooses to ignore an object file in libc.a that contains just this + function, since it's not necessary for successful compilation. + + By putting it instead in _exit.o, which is already used by crt0.c, + the linker sees __psp_libc_init and resolves the symbol properly. +*/ +void __psp_libc_init(int argc, char *argv[]) +{ + (void) argc; + + /* Initialize cwd from this program's path */ + __psp_init_cwd(argv[0]); + + /* Initialize filedescriptor management */ + __psp_fdman_init(); +} + +#endif /* F__exit */ + +#ifdef F__rename +int _rename(const char *old, const char *new) +{ + char oldname[MAXPATHLEN + 1]; + char newname[MAXPATHLEN + 1]; + + if(__psp_path_absolute(old, oldname, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + if(__psp_path_absolute(new, newname, MAXPATHLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __psp_set_errno(sceIoRename(oldname, newname)); +} +#endif + +#ifdef F_nanosleep +/* note: we don't use rem as we have no signals */ +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + if( req == NULL ) + return EFAULT; + + if( rem != NULL ) { + rem->tv_sec = 0; + rem->tv_nsec = 0; + } + + sceKernelDelayThreadCB( 1000000 * req->tv_sec + (req->tv_nsec / 1000) ); + + return 0; +} +#endif +