Mail Archives: djgpp-workers/2002/12/19/12:31:41
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 -