summaryrefslogtreecommitdiff
path: root/test_utils
diff options
context:
space:
mode:
authorMartin Matuska <martin@matuska.org>2019-04-13 21:51:03 +0200
committerMartin Matuska <martin@matuska.org>2019-04-13 21:54:29 +0200
commitb17df5e194724f7e83fa028471f00db1a78f511a (patch)
tree7459ca085ab92ad808fd5fb333b536ab5539824e /test_utils
parent40f72fed535be6a7236e91aef3aad641b71f9168 (diff)
downloadlibarchive-b17df5e194724f7e83fa028471f00db1a78f511a.tar.gz
Windows symlink bugfixes and improvements
Treat targets ending with /. and /.. as directory symlinks Explicitly test for file and directory symlinks Improve debug output on test failure Fix two memory allocations
Diffstat (limited to 'test_utils')
-rw-r--r--test_utils/test_common.h6
-rw-r--r--test_utils/test_main.c82
2 files changed, 70 insertions, 18 deletions
diff --git a/test_utils/test_common.h b/test_utils/test_common.h
index 154a6964..7538d8cb 100644
--- a/test_utils/test_common.h
+++ b/test_utils/test_common.h
@@ -220,8 +220,8 @@
assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
#define assertIsReg(pathname, mode) \
assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents) \
- assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
+#define assertIsSymlink(pathname, contents, isdir) \
+ assertion_is_symlink(__FILE__, __LINE__, pathname, contents, isdir)
/* Create a directory, report error if it fails. */
#define assertMakeDir(dirname, mode) \
assertion_make_dir(__FILE__, __LINE__, dirname, mode)
@@ -289,7 +289,7 @@ int assertion_is_dir(const char *, int, const char *, int);
int assertion_is_hardlink(const char *, int, const char *, const char *);
int assertion_is_not_hardlink(const char *, int, const char *, const char *);
int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
+int assertion_is_symlink(const char *, int, const char *, const char *, int);
int assertion_make_dir(const char *, int, const char *, int);
int assertion_make_file(const char *, int, const char *, int, int, const void *);
int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
diff --git a/test_utils/test_main.c b/test_utils/test_main.c
index cd4c772b..d9f3b19f 100644
--- a/test_utils/test_main.c
+++ b/test_utils/test_main.c
@@ -217,7 +217,7 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
DWORD attrs;
static int set;
- int ret, tmpflags;
+ int ret, tmpflags, llen, tlen;
int flags = 0;
char *src, *tgt, *p;
if (!set) {
@@ -227,10 +227,16 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
if (f == NULL)
return (0);
- tgt = malloc(strlen(target) + 1);
+ tlen = strlen(target);
+ llen = strlen(linkname);
+
+ if (tlen == 0 || llen == 0)
+ return (0);
+
+ tgt = malloc((tlen + 1) * sizeof(char));
if (tgt == NULL)
return (0);
- src = malloc(strlen(linkname) + 1);
+ src = malloc((llen + 1) * sizeof(char));
if (src == NULL) {
free(tgt);
return (0);
@@ -262,8 +268,8 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
*p = '\0';
/*
- * If the target equals ".", ".." or ends with a slash, it always
- * points to a directory. In this case we can set the directory flag.
+ * Each test has to specify if a file or a directory symlink
+ * should be created.
*/
if (targetIsDir) {
#if defined(SYMBOLIC_LINK_FLAG_DIRECTORY)
@@ -1705,23 +1711,30 @@ assertion_is_reg(const char *file, int line, const char *pathname, int mode)
return (1);
}
-/* Check whether 'pathname' is a symbolic link. If 'contents' is
- * non-NULL, verify that the symlink has those contents. */
+/*
+ * Check whether 'pathname' is a symbolic link. If 'contents' is
+ * non-NULL, verify that the symlink has those contents.
+ *
+ * On platforms with directory symlinks, set isdir to 0 to test for a file
+ * symlink and to 1 to test for a directory symlink. On other platforms
+ * the variable is ignored.
+ */
static int
is_symlink(const char *file, int line,
- const char *pathname, const char *contents)
+ const char *pathname, const char *contents, int isdir)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
HANDLE h;
DWORD inbytes;
REPARSE_DATA_BUFFER *buf;
+ BY_HANDLE_FILE_INFORMATION st;
size_t len, len2;
wchar_t *linknamew, *contentsw;
const char *p;
char *s, *pn;
int ret = 0;
BYTE *indata;
- DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |
+ static DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OPEN_REPARSE_POINT;
/* Replace slashes with backslashes in pathname */
@@ -1741,8 +1754,39 @@ is_symlink(const char *file, int line,
h = CreateFileA(pn, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
flag, NULL);
free(pn);
- if (h == INVALID_HANDLE_VALUE)
+ if (h == INVALID_HANDLE_VALUE) {
+ failure_start(file, line, "Can't access %s\n", pathname);
+ failure_finish(NULL);
return (0);
+ }
+ ret = GetFileInformationByHandle(h, &st);
+ if (ret == 0) {
+ failure_start(file, line,
+ "Can't stat: %s", pathname);
+ failure_finish(NULL);
+ } else if ((st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+ failure_start(file, line,
+ "Not a symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (isdir && ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
+ failure_start(file, line,
+ "Not a directory symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (!isdir &&
+ ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
+ failure_start(file, line,
+ "Not a file symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (ret == 0) {
+ CloseHandle(h);
+ return (0);
+ }
indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata,
@@ -1750,6 +1794,9 @@ is_symlink(const char *file, int line,
CloseHandle(h);
if (ret == 0) {
free(indata);
+ failure_start(file, line,
+ "Could not retrieve symlink target: %s", pathname);
+ failure_finish(NULL);
return (0);
}
@@ -1757,7 +1804,9 @@ is_symlink(const char *file, int line,
if (buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
free(indata);
/* File is not a symbolic link */
- errno = EINVAL;
+ failure_start(file, line,
+ "Not a symlink: %s", pathname);
+ failure_finish(NULL);
return (0);
}
@@ -1801,6 +1850,7 @@ is_symlink(const char *file, int line,
ssize_t linklen;
int r;
+ (void)isdir; /* UNUSED */
assertion_count(file, line);
r = lstat(pathname, &st);
if (r != 0) {
@@ -1829,9 +1879,9 @@ is_symlink(const char *file, int line,
/* Assert that path is a symlink that (optionally) contains contents. */
int
assertion_is_symlink(const char *file, int line,
- const char *path, const char *contents)
+ const char *path, const char *contents, int isdir)
{
- if (is_symlink(file, line, path, contents))
+ if (is_symlink(file, line, path, contents, isdir))
return (1);
if (contents)
failure_start(file, line, "File %s is not a symlink to %s",
@@ -2405,10 +2455,12 @@ canSymlink(void)
* use the Win32 CreateSymbolicLink() function. */
#if defined(_WIN32) && !defined(__CYGWIN__)
value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
- && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
+ && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0",
+ 0);
#elif HAVE_SYMLINK
value = (0 == symlink("canSymlink.0", "canSymlink.1"))
- && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
+ && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0",
+ 0);
#endif
return (value);
}