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

Reply via email to