Index: c/src/exec/libnetworking/ChangeLog
===================================================================
--- c/src/exec/libnetworking/ChangeLog	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ c/src/exec/libnetworking/ChangeLog	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -1,2 +1,7 @@
+2001-10-18	Eric Norum <eric.norum@usask.ca>
+
+	* lib/tftpDriver.c: Properly handles ../ components in chdir() and
+	open() operations within the TFTP file system.
+
 2001-10-12	Mike Siers <mikes@poliac.com>
 
Index: c/src/exec/libnetworking/lib/tftpDriver.c
===================================================================
--- c/src/exec/libnetworking/lib/tftpDriver.c	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ c/src/exec/libnetworking/lib/tftpDriver.c	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -52,4 +52,11 @@
 
 /*
+ * Root node_access value
+ * By using the address of a local static variable
+ * we ensure a unique value for this identifier.
+ */
+#define ROOT_NODE_ACCESS    (&tftp_mutex)
+
+/*
  * Default limits
  */
@@ -150,5 +157,4 @@
  * Number of streams open at the same time
  */
-
 static rtems_id tftp_mutex;
 static int nStreams;
@@ -195,5 +201,5 @@
 
   temp_mt_entry->fs_info                = NULL;
-  temp_mt_entry->mt_fs_root.node_access = NULL;
+  temp_mt_entry->mt_fs_root.node_access = ROOT_NODE_ACCESS;
 
   /*
@@ -425,7 +431,61 @@
 )
 {  
+  pathloc->node_access = NULL;
   set_errno_and_return_minus_one( EIO );    
 }
 
+/*
+ * Convert a path to canonical form
+ */
+static void
+fixPath (char *path)
+{
+    char *inp, *outp, *base;
+
+    outp = inp = path;
+    base = NULL;
+    for (;;) {
+        if (inp[0] == '.') {
+            if (inp[1] == '\0')
+                break;
+            if (inp[1] == '/') {
+                inp += 2;
+                continue;
+            }
+            if (inp[1] == '.') {
+                if (inp[2] == '\0') {
+                    if ((base != NULL) && (outp > base)) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    break;
+                }
+                if (inp[2] == '/') {
+                    inp += 3;
+                    if (base == NULL)
+                        continue;
+                    if (outp > base) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    continue;
+                }
+            }
+        }
+        if (base == NULL)
+            base = inp;
+        while (inp[0] != '/') {
+            if ((*outp++ = *inp++) == '\0')
+                return;
+        }
+        *outp++ = '/';
+        while (inp[0] == '/')
+            inp++;
+    }
+    *outp = '\0';
+    return;
+}
 
 static int rtems_tftp_eval_path(  
@@ -442,4 +502,5 @@
      */
     if (pathname[strlen(pathname)-1] == '/') {
+        int isRelative = (pathloc->node_access != ROOT_NODE_ACCESS);
         char *cp;
         
@@ -449,10 +510,22 @@
         if (flags)
             set_errno_and_return_minus_one( EISDIR );
-        cp = strdup (pathname);
-        if (cp == NULL)
-            set_errno_and_return_minus_one( ENOMEM );
+        if (isRelative) {
+            cp = malloc (strlen(pathloc->node_access)+strlen(pathname)+1);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+            strcpy (cp, pathloc->node_access);
+            strcat (cp, pathname);
+        }
+        else {
+            cp = strdup (pathname);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+        }
+        fixPath (cp);
         pathloc->node_access = cp;
         return 0;
     }
+    if (pathloc->node_access != ROOT_NODE_ACCESS)
+        pathloc->node_access = 0;
 
     /*
@@ -462,5 +535,4 @@
     if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
         set_errno_and_return_minus_one( EINVAL );
-    pathloc->node_access = NULL;
     return 0;
 }
@@ -708,20 +780,4 @@
     }
     else {
-        /*
-         * Skip any leading ./ or ../ components.
-         */
-        for (;;) {
-            while (*new_name == '/')
-                new_name++;
-            if ((new_name[0] == '.') && (new_name[1] == '/')) {
-                new_name += 2;
-                continue;
-            }
-            if ((new_name[0] == '.') && (new_name[1] == '.') && (new_name[2] == '/')) {
-                new_name += 3;
-                continue;
-            }
-            break;
-        }
         s1 = rtems_filesystem_current.node_access;
     }
@@ -731,4 +787,5 @@
     strcpy (full_path_name, s1);
     strcat (full_path_name, new_name);
+    fixPath (full_path_name);
     err = rtems_tftp_open_worker (iop, full_path_name, flags, mode);
     free (full_path_name);
@@ -946,5 +1003,5 @@
 )
 {
-    if (pathloc->node_access) {
+    if (pathloc->node_access && (pathloc->node_access != ROOT_NODE_ACCESS)) {
         free (pathloc->node_access);
         pathloc->node_access = NULL;
Index: c/src/libnetworking/ChangeLog
===================================================================
--- c/src/libnetworking/ChangeLog	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ c/src/libnetworking/ChangeLog	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -1,2 +1,7 @@
+2001-10-18	Eric Norum <eric.norum@usask.ca>
+
+	* lib/tftpDriver.c: Properly handles ../ components in chdir() and
+	open() operations within the TFTP file system.
+
 2001-10-12	Mike Siers <mikes@poliac.com>
 
Index: c/src/libnetworking/lib/tftpDriver.c
===================================================================
--- c/src/libnetworking/lib/tftpDriver.c	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ c/src/libnetworking/lib/tftpDriver.c	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -52,4 +52,11 @@
 
 /*
+ * Root node_access value
+ * By using the address of a local static variable
+ * we ensure a unique value for this identifier.
+ */
+#define ROOT_NODE_ACCESS    (&tftp_mutex)
+
+/*
  * Default limits
  */
@@ -150,5 +157,4 @@
  * Number of streams open at the same time
  */
-
 static rtems_id tftp_mutex;
 static int nStreams;
@@ -195,5 +201,5 @@
 
   temp_mt_entry->fs_info                = NULL;
-  temp_mt_entry->mt_fs_root.node_access = NULL;
+  temp_mt_entry->mt_fs_root.node_access = ROOT_NODE_ACCESS;
 
   /*
@@ -425,7 +431,61 @@
 )
 {  
+  pathloc->node_access = NULL;
   set_errno_and_return_minus_one( EIO );    
 }
 
+/*
+ * Convert a path to canonical form
+ */
+static void
+fixPath (char *path)
+{
+    char *inp, *outp, *base;
+
+    outp = inp = path;
+    base = NULL;
+    for (;;) {
+        if (inp[0] == '.') {
+            if (inp[1] == '\0')
+                break;
+            if (inp[1] == '/') {
+                inp += 2;
+                continue;
+            }
+            if (inp[1] == '.') {
+                if (inp[2] == '\0') {
+                    if ((base != NULL) && (outp > base)) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    break;
+                }
+                if (inp[2] == '/') {
+                    inp += 3;
+                    if (base == NULL)
+                        continue;
+                    if (outp > base) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    continue;
+                }
+            }
+        }
+        if (base == NULL)
+            base = inp;
+        while (inp[0] != '/') {
+            if ((*outp++ = *inp++) == '\0')
+                return;
+        }
+        *outp++ = '/';
+        while (inp[0] == '/')
+            inp++;
+    }
+    *outp = '\0';
+    return;
+}
 
 static int rtems_tftp_eval_path(  
@@ -442,4 +502,5 @@
      */
     if (pathname[strlen(pathname)-1] == '/') {
+        int isRelative = (pathloc->node_access != ROOT_NODE_ACCESS);
         char *cp;
         
@@ -449,10 +510,22 @@
         if (flags)
             set_errno_and_return_minus_one( EISDIR );
-        cp = strdup (pathname);
-        if (cp == NULL)
-            set_errno_and_return_minus_one( ENOMEM );
+        if (isRelative) {
+            cp = malloc (strlen(pathloc->node_access)+strlen(pathname)+1);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+            strcpy (cp, pathloc->node_access);
+            strcat (cp, pathname);
+        }
+        else {
+            cp = strdup (pathname);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+        }
+        fixPath (cp);
         pathloc->node_access = cp;
         return 0;
     }
+    if (pathloc->node_access != ROOT_NODE_ACCESS)
+        pathloc->node_access = 0;
 
     /*
@@ -462,5 +535,4 @@
     if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
         set_errno_and_return_minus_one( EINVAL );
-    pathloc->node_access = NULL;
     return 0;
 }
@@ -708,20 +780,4 @@
     }
     else {
-        /*
-         * Skip any leading ./ or ../ components.
-         */
-        for (;;) {
-            while (*new_name == '/')
-                new_name++;
-            if ((new_name[0] == '.') && (new_name[1] == '/')) {
-                new_name += 2;
-                continue;
-            }
-            if ((new_name[0] == '.') && (new_name[1] == '.') && (new_name[2] == '/')) {
-                new_name += 3;
-                continue;
-            }
-            break;
-        }
         s1 = rtems_filesystem_current.node_access;
     }
@@ -731,4 +787,5 @@
     strcpy (full_path_name, s1);
     strcat (full_path_name, new_name);
+    fixPath (full_path_name);
     err = rtems_tftp_open_worker (iop, full_path_name, flags, mode);
     free (full_path_name);
@@ -946,5 +1003,5 @@
 )
 {
-    if (pathloc->node_access) {
+    if (pathloc->node_access && (pathloc->node_access != ROOT_NODE_ACCESS)) {
         free (pathloc->node_access);
         pathloc->node_access = NULL;
Index: cpukit/libnetworking/ChangeLog
===================================================================
--- cpukit/libnetworking/ChangeLog	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ cpukit/libnetworking/ChangeLog	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -1,2 +1,7 @@
+2001-10-18	Eric Norum <eric.norum@usask.ca>
+
+	* lib/tftpDriver.c: Properly handles ../ components in chdir() and
+	open() operations within the TFTP file system.
+
 2001-10-12	Mike Siers <mikes@poliac.com>
 
Index: cpukit/libnetworking/lib/tftpDriver.c
===================================================================
--- cpukit/libnetworking/lib/tftpDriver.c	(revision f20a20b4c3d45aaf71c3fcf34cb03041b92b1415)
+++ cpukit/libnetworking/lib/tftpDriver.c	(revision dfe5a4e353b4f34150b755a7ea419c52f749aaaa)
@@ -52,4 +52,11 @@
 
 /*
+ * Root node_access value
+ * By using the address of a local static variable
+ * we ensure a unique value for this identifier.
+ */
+#define ROOT_NODE_ACCESS    (&tftp_mutex)
+
+/*
  * Default limits
  */
@@ -150,5 +157,4 @@
  * Number of streams open at the same time
  */
-
 static rtems_id tftp_mutex;
 static int nStreams;
@@ -195,5 +201,5 @@
 
   temp_mt_entry->fs_info                = NULL;
-  temp_mt_entry->mt_fs_root.node_access = NULL;
+  temp_mt_entry->mt_fs_root.node_access = ROOT_NODE_ACCESS;
 
   /*
@@ -425,7 +431,61 @@
 )
 {  
+  pathloc->node_access = NULL;
   set_errno_and_return_minus_one( EIO );    
 }
 
+/*
+ * Convert a path to canonical form
+ */
+static void
+fixPath (char *path)
+{
+    char *inp, *outp, *base;
+
+    outp = inp = path;
+    base = NULL;
+    for (;;) {
+        if (inp[0] == '.') {
+            if (inp[1] == '\0')
+                break;
+            if (inp[1] == '/') {
+                inp += 2;
+                continue;
+            }
+            if (inp[1] == '.') {
+                if (inp[2] == '\0') {
+                    if ((base != NULL) && (outp > base)) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    break;
+                }
+                if (inp[2] == '/') {
+                    inp += 3;
+                    if (base == NULL)
+                        continue;
+                    if (outp > base) {
+                        outp--;
+                        while ((outp > base) && (outp[-1] != '/'))
+                            outp--;
+                    }
+                    continue;
+                }
+            }
+        }
+        if (base == NULL)
+            base = inp;
+        while (inp[0] != '/') {
+            if ((*outp++ = *inp++) == '\0')
+                return;
+        }
+        *outp++ = '/';
+        while (inp[0] == '/')
+            inp++;
+    }
+    *outp = '\0';
+    return;
+}
 
 static int rtems_tftp_eval_path(  
@@ -442,4 +502,5 @@
      */
     if (pathname[strlen(pathname)-1] == '/') {
+        int isRelative = (pathloc->node_access != ROOT_NODE_ACCESS);
         char *cp;
         
@@ -449,10 +510,22 @@
         if (flags)
             set_errno_and_return_minus_one( EISDIR );
-        cp = strdup (pathname);
-        if (cp == NULL)
-            set_errno_and_return_minus_one( ENOMEM );
+        if (isRelative) {
+            cp = malloc (strlen(pathloc->node_access)+strlen(pathname)+1);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+            strcpy (cp, pathloc->node_access);
+            strcat (cp, pathname);
+        }
+        else {
+            cp = strdup (pathname);
+            if (cp == NULL)
+                set_errno_and_return_minus_one( ENOMEM );
+        }
+        fixPath (cp);
         pathloc->node_access = cp;
         return 0;
     }
+    if (pathloc->node_access != ROOT_NODE_ACCESS)
+        pathloc->node_access = 0;
 
     /*
@@ -462,5 +535,4 @@
     if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
         set_errno_and_return_minus_one( EINVAL );
-    pathloc->node_access = NULL;
     return 0;
 }
@@ -708,20 +780,4 @@
     }
     else {
-        /*
-         * Skip any leading ./ or ../ components.
-         */
-        for (;;) {
-            while (*new_name == '/')
-                new_name++;
-            if ((new_name[0] == '.') && (new_name[1] == '/')) {
-                new_name += 2;
-                continue;
-            }
-            if ((new_name[0] == '.') && (new_name[1] == '.') && (new_name[2] == '/')) {
-                new_name += 3;
-                continue;
-            }
-            break;
-        }
         s1 = rtems_filesystem_current.node_access;
     }
@@ -731,4 +787,5 @@
     strcpy (full_path_name, s1);
     strcat (full_path_name, new_name);
+    fixPath (full_path_name);
     err = rtems_tftp_open_worker (iop, full_path_name, flags, mode);
     free (full_path_name);
@@ -946,5 +1003,5 @@
 )
 {
-    if (pathloc->node_access) {
+    if (pathloc->node_access && (pathloc->node_access != ROOT_NODE_ACCESS)) {
         free (pathloc->node_access);
         pathloc->node_access = NULL;
