From 41e61aadba3855410c5b3d97280107f51c225048 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 21 Sep 2009 14:07:44 -0600 Subject: [PATCH] test-symlinkat: enhance test * tests/test-readlink.c (main): Move guts... * tests/test-readlink.h (test_readlink): ...into new file. * tests/test-symlink.c (main): Move guts... * tests/test-symlink.h (test_symlink): ...into new file. * tests/test-symlinkat.c (main): Use new files for further coverage. (do_symlink, do_readlink): New helper functions. * modules/symlink-tests (Files): Ship new file. (Depends-on): Add stdbool. * modules/readlink-tests (Files): Ship new file. (Depends-on): Add stdbool. * modules/symlinkat-tests (Files): Use new files. Signed-off-by: Eric Blake --- ChangeLog | 16 +++++++ modules/readlink-tests | 2 + modules/symlink-tests | 2 + modules/symlinkat-tests | 2 + tests/test-readlink.c | 83 ++----------------------------------- tests/test-readlink.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-symlink.c | 52 ++--------------------- tests/test-symlink.h | 77 ++++++++++++++++++++++++++++++++++ tests/test-symlinkat.c | 91 ++++++++++++++++++++-------------------- 9 files changed, 262 insertions(+), 171 deletions(-) create mode 100644 tests/test-readlink.h create mode 100644 tests/test-symlink.h diff --git a/ChangeLog b/ChangeLog index 618f1c9ad..552e8dc7b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2009-09-23 Eric Blake + test-symlinkat: enhance test + * tests/test-readlink.c (main): Move guts... + * tests/test-readlink.h (test_readlink): ...into new file. + * tests/test-symlink.c (main): Move guts... + * tests/test-symlink.h (test_symlink): ...into new file. + * tests/test-symlinkat.c (main): Use new files for further + coverage. + (do_symlink, do_readlink): New helper functions. + * modules/symlink-tests (Files): Ship new file. + (Depends-on): Add stdbool. + * modules/readlink-tests (Files): Ship new file. + (Depends-on): Add stdbool. + * modules/symlinkat-tests (Files): Use new files. + +2009-09-23 Eric Blake + readlink: document portability issue with symlink length * doc/posix-functions/lstat.texi (lstat): Mention that some file systems have bogus st_size on symlinks, and mention the diff --git a/modules/readlink-tests b/modules/readlink-tests index 84994d572..84cc326a0 100644 --- a/modules/readlink-tests +++ b/modules/readlink-tests @@ -1,7 +1,9 @@ Files: +tests/test-readlink.h tests/test-readlink.c Depends-on: +stdbool symlink configure.ac: diff --git a/modules/symlink-tests b/modules/symlink-tests index aa67405d8..9858ade2a 100644 --- a/modules/symlink-tests +++ b/modules/symlink-tests @@ -1,7 +1,9 @@ Files: +tests/test-symlink.h tests/test-symlink.c Depends-on: +stdbool configure.ac: diff --git a/modules/symlinkat-tests b/modules/symlinkat-tests index 915056837..a0dab9f53 100644 --- a/modules/symlinkat-tests +++ b/modules/symlinkat-tests @@ -1,4 +1,6 @@ Files: +tests/test-readlink.h +tests/test-symlink.h tests/test-symlinkat.c Depends-on: diff --git a/tests/test-readlink.c b/tests/test-readlink.c index 97a6788b9..1fdc2da5a 100644 --- a/tests/test-readlink.c +++ b/tests/test-readlink.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -41,89 +42,13 @@ #define BASE "test-readlink.t" +#include "test-readlink.h" + int main () { - char buf[80]; - /* Remove any leftovers from a previous partial run. */ ASSERT (system ("rm -rf " BASE "*") == 0); - /* Sanity checks of failures. Mingw lacks symlink, but readlink can - still distinguish between various errors. */ - memset (buf, 0xff, sizeof buf); - errno = 0; - ASSERT (readlink ("no_such", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlink ("no_such/", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlink ("", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlink (".", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - errno = 0; - ASSERT (readlink ("./", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - ASSERT (close (creat (BASE "file", 0600)) == 0); - errno = 0; - ASSERT (readlink (BASE "file", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - errno = 0; - ASSERT (readlink (BASE "file/", buf, sizeof buf) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (unlink (BASE "file") == 0); - - /* Now test actual symlinks. */ - if (symlink (BASE "dir", BASE "link")) - { - fputs ("skipping test: symlinks not supported on this filesystem\n", - stderr); - return 77; - } - ASSERT (mkdir (BASE "dir", 0700) == 0); - errno = 0; - ASSERT (readlink (BASE "link/", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - { - /* Up till now, no readlink has been successful, so buf should be - unchanged. */ - int i; - for (i = 0; i < sizeof buf; i++) - ASSERT (buf[i] == (char) 0xff); - } - { - size_t len = strlen (BASE "dir"); - /* When passing too small of a buffer, expect the truncated - length, or an ERANGE failure. However, a size of 0 is not - portable enough to test. */ - ssize_t result; - errno = 0; - result = readlink (BASE "link", buf, 1); - if (result == -1) - { - ASSERT (errno == ERANGE); - ASSERT (buf[0] == (char) 0xff); - } - else - { - ASSERT (result == 1); - ASSERT (buf[0] == BASE[0]); - } - ASSERT (buf[1] == (char) 0xff); - ASSERT (readlink (BASE "link", buf, len) == len); - ASSERT (strncmp (buf, BASE "dir", len) == 0); - ASSERT (buf[len] == (char) 0xff); - ASSERT (readlink (BASE "link", buf, sizeof buf) == len); - ASSERT (strncmp (buf, BASE "dir", len) == 0); - /* POSIX says rest of buf is unspecified; but in practice, it is - either left alone, or NUL-terminated. */ - ASSERT (buf[len] == '\0' || buf[len] == (char) 0xff); - } - ASSERT (rmdir (BASE "dir") == 0); - ASSERT (unlink (BASE "link") == 0); - - return 0; + return test_readlink (readlink, true); } diff --git a/tests/test-readlink.h b/tests/test-readlink.h new file mode 100644 index 000000000..996e11f3a --- /dev/null +++ b/tests/test-readlink.h @@ -0,0 +1,108 @@ +/* Tests of readlink. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Eric Blake , 2009. */ + +/* This file is designed to test both readlink(a,b,c) and + readlinkat(AT_FDCWD,a,b,c). FUNC is the function to test. Assumes + that BASE and ASSERT are already defined, and that appropriate + headers are already included. If PRINT, warn before skipping + symlink tests with status 77. */ + +static int +test_readlink (ssize_t (*func) (char const *, char *, size_t), bool print) +{ + char buf[80]; + + /* Sanity checks of failures. Mingw lacks symlink, but readlink can + still distinguish between various errors. */ + memset (buf, 0xff, sizeof buf); + errno = 0; + ASSERT (func ("no_such", buf, sizeof buf) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("no_such/", buf, sizeof buf) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("", buf, sizeof buf) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func (".", buf, sizeof buf) == -1); + ASSERT (errno == EINVAL); + errno = 0; + ASSERT (func ("./", buf, sizeof buf) == -1); + ASSERT (errno == EINVAL); + ASSERT (close (creat (BASE "file", 0600)) == 0); + errno = 0; + ASSERT (func (BASE "file", buf, sizeof buf) == -1); + ASSERT (errno == EINVAL); + errno = 0; + ASSERT (func (BASE "file/", buf, sizeof buf) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (unlink (BASE "file") == 0); + + /* Now test actual symlinks. */ + if (symlink (BASE "dir", BASE "link")) + { + if (print) + fputs ("skipping test: symlinks not supported on this filesystem\n", + stderr); + return 77; + } + ASSERT (mkdir (BASE "dir", 0700) == 0); + errno = 0; + ASSERT (func (BASE "link/", buf, sizeof buf) == -1); + ASSERT (errno == EINVAL); + { + /* Up till now, no readlink has been successful, so buf should be + unchanged. */ + int i; + for (i = 0; i < sizeof buf; i++) + ASSERT (buf[i] == (char) 0xff); + } + { + size_t len = strlen (BASE "dir"); + /* When passing too small of a buffer, expect the truncated + length, or an ERANGE failure. However, a size of 0 is not + portable enough to test. */ + ssize_t result; + errno = 0; + result = readlink (BASE "link", buf, 1); + if (result == -1) + { + ASSERT (errno == ERANGE); + ASSERT (buf[0] == (char) 0xff); + } + else + { + ASSERT (result == 1); + ASSERT (buf[0] == BASE[0]); + } + ASSERT (buf[1] == (char) 0xff); + ASSERT (func (BASE "link", buf, len) == len); + ASSERT (strncmp (buf, BASE "dir", len) == 0); + ASSERT (buf[len] == (char) 0xff); + ASSERT (func (BASE "link", buf, sizeof buf) == len); + ASSERT (strncmp (buf, BASE "dir", len) == 0); + /* POSIX says rest of buf is unspecified; but in practice, it is + either left alone, or NUL-terminated. */ + ASSERT (buf[len] == '\0' || buf[len] == (char) 0xff); + } + ASSERT (rmdir (BASE "dir") == 0); + ASSERT (unlink (BASE "link") == 0); + + return 0; +} diff --git a/tests/test-symlink.c b/tests/test-symlink.c index 9f9dda14c..9f39090e8 100644 --- a/tests/test-symlink.c +++ b/tests/test-symlink.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -40,58 +41,13 @@ #define BASE "test-symlink.t" +#include "test-symlink.h" + int main () { /* Remove any leftovers from a previous partial run. */ ASSERT (system ("rm -rf " BASE "*") == 0); - if (symlink ("nowhere", BASE "link1")) - { - fputs ("skipping test: symlinks not supported on this filesystem\n", - stderr); - return 77; - } - - /* Some systems allow the creation of 0-length symlinks as a synonym - for "."; but most reject it. */ - errno = 0; - if (symlink ("", BASE "link2") == -1) - ASSERT (errno == ENOENT || errno == EINVAL); - else - ASSERT (unlink (BASE "link2") == 0); - - /* Sanity checks of failures. */ - errno = 0; - ASSERT (symlink ("nowhere", "") == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (symlink ("nowhere", ".") == -1); - ASSERT (errno == EEXIST || errno == EINVAL); - errno = 0; - ASSERT (symlink ("somewhere", BASE "link1") == -1); - ASSERT (errno == EEXIST); - errno = 0; - ASSERT (symlink ("nowhere", BASE "link2/") == -1); - ASSERT (errno == ENOTDIR || errno == ENOENT); - ASSERT (mkdir (BASE "dir", 0700) == 0); - errno = 0; - ASSERT (symlink ("nowhere", BASE "dir") == -1); - ASSERT (errno == EEXIST); - errno = 0; - ASSERT (symlink ("nowhere", BASE "dir/") == -1); - ASSERT (errno == EEXIST); - ASSERT (close (creat (BASE "file", 0600)) == 0); - errno = 0; - ASSERT (symlink ("nowhere", BASE "file") == -1); - ASSERT (errno == EEXIST); - errno = 0; - ASSERT (symlink ("nowhere", BASE "file/") == -1); - ASSERT (errno == EEXIST || errno == ENOTDIR); - - ASSERT (rmdir (BASE "dir") == 0); - ASSERT (unlink (BASE "file") == 0); - ASSERT (unlink (BASE "link1") == 0); - - return 0; + return test_symlink (symlink, true); } diff --git a/tests/test-symlink.h b/tests/test-symlink.h new file mode 100644 index 000000000..ef5156438 --- /dev/null +++ b/tests/test-symlink.h @@ -0,0 +1,77 @@ +/* Tests of symlink. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Eric Blake , 2009. */ + +/* This file is designed to test both symlink(a,b) and + symlinkat(a,AT_FDCWD,b). FUNC is the function to test. Assumes + that BASE and ASSERT are already defined, and that appropriate + headers are already included. If PRINT, warn before skipping + symlink tests with status 77. */ + +static int +test_symlink (int (*func) (char const *, char const *), bool print) +{ + if (func ("nowhere", BASE "link1")) + { + if (print) + fputs ("skipping test: symlinks not supported on this filesystem\n", + stderr); + return 77; + } + + /* Some systems allow the creation of 0-length symlinks as a synonym + for "."; but most reject it. */ + errno = 0; + if (func ("", BASE "link2") == -1) + ASSERT (errno == ENOENT || errno == EINVAL); + else + ASSERT (unlink (BASE "link2") == 0); + + /* Sanity checks of failures. */ + errno = 0; + ASSERT (func ("nowhere", "") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nowhere", ".") == -1); + ASSERT (errno == EEXIST || errno == EINVAL); + errno = 0; + ASSERT (func ("somewhere", BASE "link1") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "link2/") == -1); + ASSERT (errno == ENOTDIR || errno == ENOENT); + ASSERT (mkdir (BASE "dir", 0700) == 0); + errno = 0; + ASSERT (func ("nowhere", BASE "dir") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "dir/") == -1); + ASSERT (errno == EEXIST); + ASSERT (close (creat (BASE "file", 0600)) == 0); + errno = 0; + ASSERT (func ("nowhere", BASE "file") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "file/") == -1); + ASSERT (errno == EEXIST || errno == ENOTDIR); + + ASSERT (rmdir (BASE "dir") == 0); + ASSERT (unlink (BASE "file") == 0); + ASSERT (unlink (BASE "link1") == 0); + + return 0; +} diff --git a/tests/test-symlinkat.c b/tests/test-symlinkat.c index 7942d27b6..4a6fe0a7b 100644 --- a/tests/test-symlinkat.c +++ b/tests/test-symlinkat.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -43,78 +44,80 @@ } \ while (0) +#define BASE "test-symlinkat.t" + +#include "test-readlink.h" +#include "test-symlink.h" + +static int dfd = AT_FDCWD; + +static int +do_symlink (char const *contents, char const *name) +{ + return symlinkat (contents, dfd, name); +} + +static ssize_t +do_readlink (char const *name, char *buf, size_t len) +{ + return readlinkat (dfd, name, buf, len); +} + int main () { char buf[80]; + int result; - /* Create handle for future use. */ - int dfd = openat (AT_FDCWD, ".", O_RDONLY); + /* Remove any leftovers from a previous partial run. */ + ASSERT (system ("rm -rf " BASE "*") == 0); + + /* Perform same checks as counterpart functions. */ + result = test_readlink (do_readlink, false); + ASSERT (test_symlink (do_symlink, false) == result); + dfd = openat (AT_FDCWD, ".", O_RDONLY); ASSERT (0 <= dfd); + ASSERT (test_readlink (do_readlink, false) == result); + ASSERT (test_symlink (do_symlink, false) == result); - /* Sanity checks of failures. Mingw lacks symlinkat, but readlinkat - can still distinguish between various errors. */ - errno = 0; - ASSERT (readlinkat (AT_FDCWD, "no_such", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlinkat (dfd, "no_such", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlinkat (AT_FDCWD, "", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlinkat (dfd, "", buf, sizeof buf) == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (readlinkat (AT_FDCWD, ".", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - errno = 0; - ASSERT (readlinkat (dfd, ".", buf, sizeof buf) == -1); - ASSERT (errno == EINVAL); - errno = 0; - ASSERT (symlinkat ("who cares", AT_FDCWD, "") == -1); - ASSERT (errno == ENOENT || errno == ENOSYS); - errno = 0; - ASSERT (symlinkat ("who cares", dfd, "") == -1); - ASSERT (errno == ENOENT || errno == ENOSYS); - - /* Skip everything else on mingw. */ + /* Now perform some cross-directory checks. Skip everything else on + mingw. */ if (HAVE_SYMLINK) { - const char *linkname = "test-symlinkat.link"; const char *contents = "don't matter!"; - int exp = strlen (contents); + ssize_t exp = strlen (contents); /* Create link while cwd is '.', then read it in '..'. */ - ASSERT (symlinkat (contents, AT_FDCWD, linkname) == 0); + ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == 0); errno = 0; - ASSERT (symlinkat (contents, dfd, linkname) == -1); + ASSERT (symlinkat (contents, dfd, BASE "link") == -1); ASSERT (errno == EEXIST); ASSERT (chdir ("..") == 0); errno = 0; - ASSERT (readlinkat (AT_FDCWD, linkname, buf, sizeof buf) == -1); + ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == -1); ASSERT (errno == ENOENT); - ASSERT (readlinkat (dfd, linkname, buf, sizeof buf) == exp); + ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); - ASSERT (unlinkat (dfd, linkname, 0) == 0); + ASSERT (unlinkat (dfd, BASE "link", 0) == 0); /* Create link while cwd is '..', then read it in '.'. */ - ASSERT (symlinkat (contents, dfd, linkname) == 0); + ASSERT (symlinkat (contents, dfd, BASE "link") == 0); ASSERT (fchdir (dfd) == 0); errno = 0; - ASSERT (symlinkat (contents, AT_FDCWD, linkname) == -1); + ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == -1); ASSERT (errno == EEXIST); buf[0] = '\0'; - ASSERT (readlinkat (AT_FDCWD, linkname, buf, sizeof buf) == exp); + ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); buf[0] = '\0'; - ASSERT (readlinkat (dfd, linkname, buf, sizeof buf) == exp); + ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); - ASSERT (unlink (linkname) == 0); + ASSERT (unlink (BASE "link") == 0); } ASSERT (close (dfd) == 0); - - return 0; + if (result == 77) + fputs ("skipping test: symlinks not supported on this filesystem\n", + stderr); + return result; } -- 2.11.0