Hi,
I've concocted this patch that adds realpath() function, and also
fixes getcwd() to allocate the buffer dynamically, and also fail if
the current directory doesn't exist. I also attached the test I used
to test the patch.
Thanks!
Pawel.
--
With best of best regards
Pawel S. Veselov
Index: src/newlib/newlib/libc/include/stdlib.h
===================================================================
--- src/newlib/newlib/libc/include/stdlib.h (revision 1172)
+++ src/newlib/newlib/libc/include/stdlib.h (working copy)
@@ -122,6 +122,7 @@
int _EXFUN(system,(const char *__string));
#ifndef __STRICT_ANSI__
+char * _EXFUN(realpath,(const char *__path, char *__resolved_path));
long _EXFUN(a64l,(const char *__input));
char * _EXFUN(l64a,(long __input));
char * _EXFUN(_l64a_r,(struct _reent *,long __input));
Index: src/newlib/newlib/libc/sys/wince/Makefile.in
===================================================================
--- src/newlib/newlib/libc/sys/wince/Makefile.in (revision 1172)
+++ src/newlib/newlib/libc/sys/wince/Makefile.in (working copy)
@@ -86,7 +86,7 @@
net_SOURCES = ascii2addr.c htons.c htonl.c inet_aton.c inet_lnaof.c inet_mkadr.c inet_net.c inet_netof.c inet_ntoa.c msnet.c wsdb.c rexec.c wsstrerror.c
-unix_SOURCES = getcwd.c getlogin.c sleep.c usleep.c vfork.c
+unix_SOURCES = getcwd.c getlogin.c sleep.c usleep.c vfork.c realpath.c
celib_SOURCES = cecopyfile.c cefileattr.c cefindfile.c cefixpath.c ceirda.c ceutil.c cethread.c cemakeunixpath.c cemovefile.c cecreatefile.c cecreatefilemap.c ceregistry.c cecurrentdir.c ceprofile.c ceshared2.c ceremovedir.c cemisc.c
@@ -116,7 +116,7 @@
trace.o tzset_hook_r.o uid.o unistd.o utime.o main.o ascii2addr.o \
htons.o htonl.o inet_aton.o inet_lnaof.o inet_mkadr.o inet_net.o \
inet_netof.o inet_ntoa.o msnet.o wsdb.o rexec.o wsstrerror.o getcwd.o \
-getlogin.o sleep.o usleep.o vfork.o cecopyfile.o cefileattr.o \
+getlogin.o realpath.o sleep.o usleep.o vfork.o cecopyfile.o cefileattr.o \
cefindfile.o cefixpath.o ceirda.o ceutil.o cethread.o cemakeunixpath.o \
cemovefile.o cecreatefile.o cecreatefilemap.o ceregistry.o \
cecurrentdir.o ceprofile.o ceshared2.o ceremovedir.o cemisc.o _crt_mt.o \
Index: src/newlib/newlib/libc/sys/wince/sys/unistd.h
===================================================================
--- src/newlib/newlib/libc/sys/wince/sys/unistd.h (revision 1172)
+++ src/newlib/newlib/libc/sys/wince/sys/unistd.h (working copy)
@@ -21,6 +21,7 @@
int _EXFUN(chdir, (const char *__path ));
int _EXFUN(chmod, (const char *__path, mode_t __mode ));
int _EXFUN(chown, (const char *__path, uid_t __owner, gid_t __group ));
+int _EXFUN(fdatasync, (int __fd));
#if defined(__CYGWIN__) || defined(__rtems__)
int _EXFUN(chroot, (const char *__path ));
#endif
Index: src/newlib/newlib/libc/sys/wince/realpath.c
===================================================================
--- src/newlib/newlib/libc/sys/wince/realpath.c (revision 0)
+++ src/newlib/newlib/libc/sys/wince/realpath.c (revision 0)
@@ -0,0 +1,165 @@
+/* realpath.c - Return the canonicalized absolute pathname */
+
+/* Written 2000 by Werner Almesberger */
+/* Adapted for WINCE */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+char *realpath(const char *path, char *resolved_path) {
+
+ char *path_copy;
+ char *aptr;
+ int res;
+ int alloced = 0;
+
+ if (!path) {
+ errno = EINVAL;
+ return NULL;
+ } else if (!*path) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ path_copy = strdup(path);
+ if (!path_copy) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ // Since this is wince, there is no way we can have '\' characters
+ // in file/dir names. So we might as well replace them with '/', won't
+ // change nothing.
+
+ aptr = path_copy;
+ while (aptr = strchr(aptr, '\\')) { *(aptr++) = '/'; }
+
+ if (*path_copy != '/') {
+
+ // then we need current directory
+ char * cwd = getcwd(0,0);
+ if (!cwd) {
+ // this should only be ENOENT, or ENOMEM
+ free(path_copy);
+ return NULL;
+ }
+
+ aptr = malloc(strlen(cwd) + strlen(path_copy) + 2);
+
+ if (aptr) {
+ strcpy(aptr, cwd);
+ strcat(aptr, "/");
+ strcpy(aptr, path_copy);
+ }
+
+ free(path_copy);
+ free(cwd);
+ if (!aptr) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ path_copy = aptr;
+ }
+
+ // remove any trailing slashes
+ aptr = path_copy + strlen(path_copy) - 1;
+ while (aptr > path_copy && *aptr == '/') { *(aptr--) = 0; }
+
+ if (!resolved_path) {
+ // since there are no symlinks on WinCE, we are lucky,
+ // the resolved path will never exceed this path
+ resolved_path = malloc(strlen(path_copy)+1);
+ alloced = 1;
+ }
+
+ *resolved_path = '/';
+ resolved_path[1] = 0; // ought to be faster than strcpy
+
+ aptr = path_copy;
+ struct stat st;
+
+ while (1) {
+
+ while (*aptr == '/') { aptr++; }
+
+ // are we done?
+ if (!*aptr) { break; }
+
+ // find next slash
+ char * slash = strchr(aptr, '/');
+ if (slash) {
+ *slash = 0;
+ }
+
+ if (*aptr == '.') {
+ if (!aptr[1]) {
+ // encountered "."
+ // nothing to do
+ if (!slash) { break; }
+ aptr = slash + 1;
+ continue;
+ }
+ if (aptr[1] == '.' && !aptr[2]) {
+ // encountered ".."
+ // so rewind the path one element back
+ char * prev_slash = strrchr(resolved_path, '/');
+ if (prev_slash == resolved_path) {
+ // if the only thing in the path now is the
+ // root, then the root just remains there
+ prev_slash++;
+ }
+ *prev_slash = 0;
+
+ if (!slash) { break; }
+ aptr = slash + 1;
+ continue;
+ }
+ }
+
+ if (resolved_path[1]) {
+ strcat(resolved_path, "/");
+ }
+
+ strcat(resolved_path, aptr);
+
+ if (slash) {
+
+ if (lstat(resolved_path, &st)) {
+
+ if (alloced) {
+ free(resolved_path);
+ }
+ free(path_copy);
+
+ errno = EACCES;
+ return NULL;
+
+ }
+
+ if (!(st.st_mode & S_IFDIR)) {
+ // there are more entries ahead, but this one is
+ // not a directory. tsk-tsk
+ if (alloced) { free(resolved_path); }
+ free(path_copy);
+ errno = ENOTDIR;
+ return NULL;
+ }
+
+ } else {
+ break;
+ }
+
+ aptr = slash + 1;
+ continue;
+
+ }
+
+ free(path_copy);
+ return resolved_path;
+
+}
+
Index: src/newlib/newlib/libc/sys/wince/getcwd.c
===================================================================
--- src/newlib/newlib/libc/sys/wince/getcwd.c (revision 1172)
+++ src/newlib/newlib/libc/sys/wince/getcwd.c (working copy)
@@ -68,9 +68,33 @@
char *
getcwd(char *buf, size_t size)
{
- /* This is NOT compliant with what Linux does.. */
- if (buf == NULL || size == 0) {
- /* ### TODO malloc a buffer here. Be careful with size-1 below */
+
+ int alloced = 0;
+
+ // realize glibc behavior to allocate buffer if the buf is 0.
+ // This is also a POSIX.1-2001 extension
+
+ if (!buf) {
+ if (!size) {
+ size = XCEGetCurrentDirectoryW(0, 0); // fastest way to get size
+ if (!size) {
+ WCETRACE(WCE_IO, "getcwd WARNING: curr dir is unset");
+ // ENOENT The current working directory has been unlinked.
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+
+ buf = malloc(size);
+ if (!buf) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ alloced = 1;
+
+ } else if (!size) {
+ // EINVAL The size argument is zero and buf is not a null pointer.
+ errno = EINVAL;
return(NULL);
}
@@ -78,18 +102,32 @@
if (len > size)
{
- XCEToUnixPath(buf, size-1);
- errno = ERANGE;
- return(NULL);
+ // XCEToUnixPath(buf, size-1);
+ // ^^ commented out, why do we care? the spec says:
+ // the contents of the array pointed to by buf is undefined on error.
+ errno = ERANGE;
+ return(NULL);
}
else if (!len)
{
- WCETRACE(WCE_IO, "getcwd WARNING: curr dir is unset");
- return NULL;
+ WCETRACE(WCE_IO, "getcwd WARNING: curr dir is unset");
+ // ENOENT The current working directory has been unlinked.
+ // well, that's the next best thing
+ errno = ENOENT;
+ return NULL;
}
else
{
- XCEToUnixPath(buf, -1);
+ struct stat st;
+ XCEToUnixPath(buf, -1);
+ if (lstat(buf, &st)) {
+ // ENOENT The current working directory has been unlinked.
+ if (alloced) {
+ free(buf);
+ }
+ errno = ENOENT;
+ return NULL;
+ }
}
return buf;
}
Index: src/newlib/newlib/libc/sys/wince/Makefile.am
===================================================================
--- src/newlib/newlib/libc/sys/wince/Makefile.am (revision 1172)
+++ src/newlib/newlib/libc/sys/wince/Makefile.am (working copy)
@@ -8,7 +8,7 @@
net_SOURCES = ascii2addr.c htons.c htonl.c inet_aton.c inet_lnaof.c inet_mkadr.c \
inet_net.c inet_netof.c inet_ntoa.c msnet.c wsdb.c rexec.c wsstrerror.c
-unix_SOURCES = getcwd.c getlogin.c sleep.c usleep.c vfork.c
+unix_SOURCES = getcwd.c getlogin.c sleep.c usleep.c vfork.c realpath.c
celib_SOURCES = cecopyfile.c cefileattr.c cefindfile.c cefixpath.c ceirda.c ceutil.c cethread.c cemakeunixpath.c \
cemovefile.c cecreatefile.c cecreatefilemap.c ceregistry.c cecurrentdir.c ceprofile.c \
ceshared2.c ceremovedir.c cemisc.c
Index: src/newlib/ChangeLog.cegcc
===================================================================
--- src/newlib/ChangeLog.cegcc (revision 1172)
+++ src/newlib/ChangeLog.cegcc (working copy)
@@ -1,3 +1,12 @@
+2008-09-12 Pawel Veselov <[EMAIL PROTECTED]>
+ * newlib/newlib/libc/include/stdlib.h : added realpath() declaration
+ * newlib/libc/sys/wince/Makefile.in newlib/libc/sys/wince/Makefile.am :
+ compile realpath.c
+ * newlib/libc/sys/wince/sys/unistd.h : declare fdatasync()
+ * newlib/libc/sys/wince/realpath.c : defines realpath(), Linux compliant
+ * newlib/libc/sys/wince/getcwd.c : buffer is now allocated if NULL.
+ ENOENT is returned if current directory doesn't exist
+
2008-08-29 Pawel Veselov <[EMAIL PROTECTED]>
* newlib/libc/sys/wince/io.c (fsync, fdatasync) : Implement.
* newlib/libc/sys/wince/sys/io.h newlib/libc/sys/wince/io.c
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
static int test(void);
int main(int argc, char ** argv) {
printf("executing test\n");
int rc = test();
if (rc) {
printf("*** FAILED ***\n");
} else {
printf("*** OK ***\n");
}
fflush(stdout);
fflush(stderr);
fdatasync(1);
fdatasync(2);
return rc;
}
int test() {
char * cwd = getcwd(0,0);
if (!cwd) {
perror("initial cwd");
} else {
printf("initial cwd : %s\n", cwd);
free(cwd);
}
fprintf(stdout, "creating test directory...\n");
if (mkdir("/dir_test", 0777)) {
perror("mkdir");
return 1;
}
printf("testing realpath('/')...\n");
cwd = realpath("/", 0);
if (!cwd) {
perror("realpath('/')");
return 1;
}
printf("realpath('/') = %s\n", cwd);
free(cwd);
printf("testing realpath('/non-existing-dir')\n");
cwd = realpath("/dom-dom-shouldn't be found///", 0);
if (!cwd) {
perror("realpath('/dom-dom-not-found')");
return 1;
}
printf("realpath(non-existent file) : %s\n", cwd);
free(cwd);
printf("testing realpath('/non-existing-dir/non-existing-dir')...\n");
cwd = realpath("/this_would_not_be_found/not_found/not_found", 0);
if (cwd) {
printf("error: realpath(not_found_dirs) returned %s\n", cwd);
return 1;
}
perror("realpath(/notfound) (should fail)");
printf("changing directory to test one...\n");
if (chdir("/dir_test")) {
perror("chdir");
return 1;
}
printf("checking current directory...\n");
cwd = getcwd(0,0);
if (!cwd) {
perror("getcwd");
return 1;
}
printf("getcwd() : %s\n", cwd);
free(cwd);
printf("checking realpath('.')...\n");
cwd = realpath(".", 0);
if (!cwd) {
perror("realpath('.');");
return 1;
}
printf("realpath('.') = %s\n", cwd);
free(cwd);
printf("checking realpath('./nothing/')...\n");
cwd = realpath("./nothing/", 0);
if (!cwd) {
perror("realpath('./nothing/')");
return 1;
}
printf("realpath('./nothing') = %s\n", cwd);
free(cwd);
printf("checking realpath(..)...\n");
cwd = realpath("..", 0);
if (!cwd) {
perror("realpath()");
return 1;
}
printf("result=%s\n", cwd);
free(cwd);
printf("checking realpath('../../dir_test/1')...\n");
cwd = realpath("..\\..\\dir_test/1", 0);
if (!cwd) {
perror("realpath()");
return 1;
}
printf("result=%s\n", cwd);
free(cwd);
printf("checkint realpath(dots-dots)...\n");
cwd = realpath("./../dir_test/./././././././../dir_test/../15", 0);
if (!cwd) {
perror("realpath()");
return 1;
}
printf("result=%s\n", cwd);
free(cwd);
printf("removing test directory...\n");
if (rmdir("/dir_test")) {
perror("rmdir(/dir_test)");
return 1;
}
printf("checking current directory...\n");
cwd = getcwd(0,0);
if (cwd) {
printf("cwd returned %s, but should've failed!\n", cwd);
return 1;
}
perror("getcwd(), but it should've failed");
printf("checking realpath(.)...\n");
cwd = realpath(".", 0);
if (cwd) {
printf("returned %s (should've failed!)\n", cwd);
return 1;
}
perror("realpath(should fail)");
printf("checking realpath(..)...\n");
if (cwd) {
printf("returned %s (should've failed)\n", cwd);
return 1;
}
perror("realpath(should fail)");
printf("checking realpath('//////////////')...\n");
cwd = realpath("///////////////////", 0);
if (!cwd) {
perror("realpath()");
return 1;
}
printf("result : %s\n", cwd);
free(cwd);
return 0;
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Cegcc-devel mailing list
Cegcc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/cegcc-devel