delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/12/19/12:31:41

Date: Thu, 19 Dec 2002 17:31:59 +0000
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: __solve_symlinks and multiple slashes [PATCH]
Message-Id: <E18P4WC-0001el-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Below is a patch that fixes the issues with __solve_symlinks
and multiple consecutive slashes. I've also heavily updated
the test program to test these cases and also some cases
involving '..' and relative/absolute paths. The last dynamic
test case fails, because it uses one '..' too many.

I've tested these patches by running the fileutils test suite
with rebuilt fileutils, sh-utils and textutils. There were
no regressions in the fileutils test suite - in fact, it worked
much better, since the {file,sh-,text}utils could cope
with paths like c://tmp/foo.

OK to commit?

Bye, Rich =]

Index: src/libc/compat/unistd/xsymlink.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/xsymlink.c,v
retrieving revision 1.5
diff -p -c -3 -r1.5 xsymlink.c
*** src/libc/compat/unistd/xsymlink.c	26 Aug 2000 18:46:09 -0000	1.5
--- src/libc/compat/unistd/xsymlink.c	19 Dec 2002 17:27:56 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
  
  /* Written by Laurynas Biveinis                                      */
*************** int __solve_symlinks(const char * __syml
*** 163,172 ****
     return 1;
  }
  
  static void advance(char ** s, char ** e)
  {
     *s = strpbrk(*s + 1, "/\\");
     if (*s)
!      (*s)++;
!    *e = strpbrk(*e + 1, "/\\");
  }
--- 164,180 ----
     return 1;
  }
  
+ /* Advance to the next portion of the path. Cope with multiple slashes. */
  static void advance(char ** s, char ** e)
  {
     *s = strpbrk(*s + 1, "/\\");
     if (*s)
!    {
!      while ((**s == '/') || (**s == '\\'))
!        (*s)++;
!    }
! 
!    while ((**e == '/') || (**e == '\\'))
!      (*e)++;
!    *e = strpbrk(*e, "/\\");
  }
Index: tests/libc/compat/unistd/xsymlink.c
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/compat/unistd/xsymlink.c,v
retrieving revision 1.4
diff -p -c -3 -r1.4 xsymlink.c
*** tests/libc/compat/unistd/xsymlink.c	26 May 2002 16:12:19 -0000	1.4
--- tests/libc/compat/unistd/xsymlink.c	19 Dec 2002 17:27:57 -0000
***************
*** 9,19 ****
   *   7. The same with DOS-style absolute path
   *   8. Real file in a symlink subdir in a symlink subdir
   *   9. Symlink in a subdir to file in an upper dir
   * Any unhandled cases are more than welcome.
   *
   * And following are failure tests:
!  *  11. Simple symlink loop.
!  *  12. Symlink loop across directories
   *
   *     TODO: device a test, where symlink expands to absolute path, which,
   *  in turn, has symlinks somewhere inside. There was such a test once, but
--- 9,28 ----
   *   7. The same with DOS-style absolute path
   *   8. Real file in a symlink subdir in a symlink subdir
   *   9. Symlink in a subdir to file in an upper dir
+  *  10. 3 with a double-slash
+  *  11. 7 with a double-slash
+  *  12. 8 with a double-slash
+  *  13. Regular file
   * Any unhandled cases are more than welcome.
   *
+  * There are some tests based on the current-working directory:
+  *   1. An absolute path using '..' to navigate through the directories.
+  *   2. A relative path using a drive letter and '..'.
+  *   3. A relative path using a drive letter and one too many '..' over 2.
+  *
   * And following are failure tests:
!  *   1. Simple symlink loop.
!  *   2. Symlink loop across directories
   *
   *     TODO: device a test, where symlink expands to absolute path, which,
   *  in turn, has symlinks somewhere inside. There was such a test once, but
***************
*** 24,39 ****
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <libc/symlink.h>
  #include <sys/stat.h>
  
! static void test_success(const char * slink, const char * expect);
! static void test_failure(const char * slink);
  
! static int test_num = 0;
  
  int main(void)
  {
     if (!__file_exists("test1") || !__file_exists("test4") ||
         !__file_exists("test5") || !__file_exists("dirtest") ||
         !__file_exists("fail1") || !__file_exists("fail2") ||
--- 33,89 ----
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
+ #include <limits.h>
  #include <libc/symlink.h>
  #include <sys/stat.h>
  
! typedef struct {
!   const char *src;    /* Source: includes symlink(s) */
!   const char *target; /* Target of the symlink */
! } test_success_t;
! 
! static const test_success_t tests_success[] = {
!   { "test1", "file1" },
!   { "test4", "file2" },
!   { "dir1/test1", "dir1/file1" },
!   { "dirtest/file1", "dir1/file1" },
!   { "dirtest/test1", "dir1/file1" },
!   { "dirtest/test2", "/dev/env/DJDIR/bin/gcc.exe" },
!   { "dirtest/test3", "c:\\autoexec.bat" },
!   { "dirtest/test6/file", "dir1/dir2/file" },
!   { "dir1/test7", "file" },
! 
!   /* Check that __solve_symlinks copes with double-slashes. */
!   { "dir1//test1", "dir1/file1" },
!   { "dirtest//test3", "c:\\autoexec.bat" },
!   { "dirtest//test6//file", "dir1/dir2/file" },
! 
!   /* Non-symlinks */
!   { "makefile", "makefile" }
! };
! 
! static const int n_tests_success
! = sizeof(tests_success) / sizeof(tests_success[0]);
  
! static const char *tests_failure[] = {
!   "fail1",
!   "fail3"
! };
! 
! static const int n_tests_failure
! = sizeof(tests_failure) / sizeof(tests_failure[0]);
! 
! static int test_success(const int test_num,
! 			const char * slink,
! 			const char * expect);
! 
! static int test_failure(const int test_num, const char * slink);
  
  int main(void)
  {
+    int ok = 1;
+    int ret, i, j;
+ 
     if (!__file_exists("test1") || !__file_exists("test4") ||
         !__file_exists("test5") || !__file_exists("dirtest") ||
         !__file_exists("fail1") || !__file_exists("fail2") ||
*************** int main(void)
*** 46,68 ****
         fprintf(stderr, "Required data files not found");
         exit(1);
     }
!    printf("Running readlink() testsuite:\n");
!    test_success("test1", "file1");
!    test_success("test4", "file2");
!    test_success("dir1/test1", "dir1/file1");
!    test_success("dirtest/file1", "dir1/file1");
!    test_success("dirtest/test1", "dir1/file1");
!    test_success("dirtest/test2", "/dev/env/DJDIR/bin/gcc.exe");
!    test_success("dirtest/test3", "c:\\autoexec.bat");
!    test_success("dirtest/test6/file", "dir1/dir2/file");
!    test_success("dir1/test7", "file");
!    test_failure("fail1");
!    test_failure("fail3");
!    printf("Done.\n");
!    return 0;
  }
  
! static void test_success(const char * slink, const char * expect)
  {
     char real_name[FILENAME_MAX + 1];
     char real_fixed[FILENAME_MAX + 1];
--- 96,242 ----
         fprintf(stderr, "Required data files not found");
         exit(1);
     }
!    puts("Running __solve_symlinks() and readlink() testsuite:");
! 
!    puts("Tests that check __solve_symlinks() works:");
!    for (i = 0; i < n_tests_success; i++) {
!      ret = test_success(i + 1, tests_success[i].src, tests_success[i].target);
!      if (!ret)
!        ok = 0;
!    }
! 
!    /* Construct some tests with relative paths. */
!    puts("Tests that check __solve_symlinks() based on current directory:");
!    {
!      char cwd[PATH_MAX], path[PATH_MAX + 1];
!      test_success_t test;
!      int n_slashes = 0;
!      char *cwd_without_drive = cwd;
!      char *ptr = NULL;
! 
!      if (getcwd(cwd, sizeof(cwd) - 1) == NULL)
!      {
!        fprintf(stderr, "Error: Unable to get current working directory\n");
!        return(EXIT_FAILURE);
!      }
! 
!      if (cwd[0] && (cwd[1] == ':'))
!        cwd_without_drive = cwd + 2;
! 
!      /* Count the number of slashes in the current directory => number
!       * of '..' we can use. */
!      for (ptr = strpbrk(cwd, "/\\"), n_slashes = 0;
! 	  ptr != NULL;
! 	  ptr = strpbrk(ptr + 1, "/\\"), n_slashes++) {;}
! 
!      j = 0;
! 
!      /* Try tests_success[0] with an absolute path with '..'. */
!      j++;
! 
!      strcpy(path, cwd);
!      for (i = 0; i < n_slashes; i++)
!      {
!        strcat(path, "/..");
!      }
!      strcat(path, cwd_without_drive);
!      strcat(path, "/");
!      strcat(path, tests_success[0].src);
! 
!      test.src    = path;
!      test.target = tests_success[0].target;
! 
!      printf("Test %d: Solving %s\n", j, test.src);
!      ret = test_success(j, test.src, test.target);
!      if (!ret)
!        ok = 0;
! 
!      /* Try tests_success[0] with a drive-letter and relative path
!       * with '..'. */
!      j++;
! 
!      if (cwd[0] && (cwd[1] == ':'))
!      {
!        path[0] = cwd[0];
!        path[1] = cwd[1];
!        path[2] = '\0';
!        for (i = 0; i < n_slashes; i++)
! 	 {
! 	   if (i)
! 	     strcat(path, "/..");
! 	   else
! 	     strcat(path, "..");
! 	 }
!        strcat(path, cwd_without_drive);
!        strcat(path, "/");
!        strcat(path, tests_success[0].src);
! 
!        test.src    = path;
!        test.target = tests_success[0].target;
! 
!        printf("Test %d: Solving %s\n", j, test.src);
!        ret = test_success(j, test.src, test.target);
!        if (!ret)
! 	 ok = 0;
!      }
!      else
!      {
!        printf("Test %d: No drive letter - skipping\n", j);
!      }
! 
!      /* Try tests_success[0] with a drive-letter and relative path
!       * with too many '..'. */
!      j++;
! 
!      if (cwd[0] && (cwd[1] == ':'))
!      {
!        path[0] = cwd[0];
!        path[1] = cwd[1];
!        path[2] = '\0';
!        for (i = 0; i <= n_slashes; i++)
! 	 {
! 	   if (i)
! 	     strcat(path, "/..");
! 	   else
! 	     strcat(path, "..");
! 	 }
!        strcat(path, cwd_without_drive);
!        strcat(path, "/");
!        strcat(path, tests_success[0].src);
! 
!        test.src    = path;
!        test.target = tests_success[0].target;
! 
!        printf("Test %d: Solving %s\n", j, test.src);
!        ret = test_success(j, test.src, test.target);
!        if (!ret)
! 	 ok = 0;
!      }
!      else
!      {
!        printf("Test %d: No drive letter - skipping\n", j);
!      }
!    }
! 
!    puts("Tests that check __solve_symlinks() failure cases:");
!    for (i = 0; i < n_tests_failure; i++) {
!      ret = test_failure(i + 1, tests_failure[i]);
!      if (!ret)
!        ok = 0;
!    }
! 
!    if (ok) {
!      puts("PASS");
!      return(EXIT_SUCCESS);
!    } else {
!      puts("FAIL");
!      return(EXIT_FAILURE);
!    }
  }
  
! static int test_success(const int test_num,
! 			const char * slink,
! 			const char * expect)
  {
     char real_name[FILENAME_MAX + 1];
     char real_fixed[FILENAME_MAX + 1];
*************** static void test_success(const char * sl
*** 70,76 ****
     char err_buf[50];
     if (!__solve_symlinks(slink, real_name))
     {
!       sprintf(err_buf, "Test %d failed ", ++test_num);
        perror(err_buf);
        exit(1);
     }
--- 244,250 ----
     char err_buf[50];
     if (!__solve_symlinks(slink, real_name))
     {
!       sprintf(err_buf, "Test %d failed ", test_num);
        perror(err_buf);
        exit(1);
     }
*************** static void test_success(const char * sl
*** 83,94 ****
              test_num);
        fprintf(stderr, "Returned path: %s\n", real_fixed);
        fprintf(stderr, "Expected path: %s\n", expect_fixed);
!       exit(1);
     }
     printf("Test %d passed\n", test_num);
  }
  
! static void test_failure(const char * slink)
  {
     char buf[FILENAME_MAX + 1];
     char err_buf[50];
--- 257,269 ----
              test_num);
        fprintf(stderr, "Returned path: %s\n", real_fixed);
        fprintf(stderr, "Expected path: %s\n", expect_fixed);
!       return(0);
     }
     printf("Test %d passed\n", test_num);
+    return(1);
  }
  
! static int test_failure(const int test_num, const char * slink)
  {
     char buf[FILENAME_MAX + 1];
     char err_buf[50];
*************** static void test_failure(const char * sl
*** 97,110 ****
     {
        fprintf(stderr,
              "Test %d failed - __solve_symlinks suceeds when it should fail\n",
!             ++test_num);
        exit(1);
     }
     if (errno != ELOOP)
     {
        sprintf(err_buf, "Test %d failed - wrong errno returned ", test_num);
        perror(err_buf);
!       exit(1);
     }
     printf("Test %d passed\n", test_num);
  }
--- 272,286 ----
     {
        fprintf(stderr,
              "Test %d failed - __solve_symlinks suceeds when it should fail\n",
!             test_num);
        exit(1);
     }
     if (errno != ELOOP)
     {
        sprintf(err_buf, "Test %d failed - wrong errno returned ", test_num);
        perror(err_buf);
!       return(0);
     }
     printf("Test %d passed\n", test_num);
+    return(1);
  }

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019