From 454524cf7294021584a3005f2f3243c80b670a89 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 25 Mar 2016 14:37:16 -0700 Subject: [PATCH] new native code and test for obtaining target of symlinks --- src/CMakeLists.txt | 3 +- src/followsymlink.cpp | 90 +++++++++++++++++++++++++++++++++++++ src/followsymlink.h | 9 ++++ test/test-createsymlink.cpp | 14 +++++- 4 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 src/followsymlink.cpp create mode 100644 src/followsymlink.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfd91e9fb2..5b2ec24199 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(psl-native SHARED isexecutable.cpp setdate.cpp createhardlink.cpp - createsymlink.cpp) + createsymlink.cpp + followsymlink.cpp) target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/followsymlink.cpp b/src/followsymlink.cpp new file mode 100644 index 0000000000..40e12b9b78 --- /dev/null +++ b/src/followsymlink.cpp @@ -0,0 +1,90 @@ +//! @file followSymLink.cpp +//! @author George FLeming +//! @brief returns whether a path is a symbolic link + +#include +#include +#include +#include +#include "followsymlink.h" + +//! @brief Followsymlink determines target path of a sym link +//! +//! Followsymlink +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links +//! - ERROR_GEN_FAILURE: I/O error occurred +//! - ERROR_INVALID_NAME: file provided is not a symbolic link +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long +//! - ERROR_OUTOFMEMORY insufficient kernal memory +//! +//! @retval target path, or NULL if unsuccessful +//! + +char* FollowSymLink(const char* fileName) +{ + errno = 0; + + // Check parameters + if (!fileName) + { + errno = ERROR_INVALID_PARAMETER; + return NULL; + } + + char buffer[PATH_MAX]; + ssize_t sz = readlink(fileName, buffer, PATH_MAX); + + if (sz == -1) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case EINVAL: + errno = ERROR_INVALID_NAME; + break; + case EIO: + errno = ERROR_GEN_FAILURE; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_BAD_PATH_NAME; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTDIR: + errno = ERROR_BAD_PATH_NAME; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return NULL; + } + + buffer[sz] = '\0'; + return strndup(buffer, sz + 1); +} diff --git a/src/followsymlink.h b/src/followsymlink.h new file mode 100644 index 0000000000..fac7f5244f --- /dev/null +++ b/src/followsymlink.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* FollowSymLink(const char* fileName); + +PAL_END_EXTERNC diff --git a/test/test-createsymlink.cpp b/test/test-createsymlink.cpp index 1100d022cd..abc0646c61 100644 --- a/test/test-createsymlink.cpp +++ b/test/test-createsymlink.cpp @@ -1,12 +1,13 @@ -//! @file test-issymlink.cpp +//! @file test-createsymlink.cpp //! @author George Fleming -//! @brief Implements test for isSymLink() +//! @brief Implements test for CreateSymLink() and FollowSymLink() #include #include #include #include "issymlink.h" #include "createsymlink.h" +#include "followsymlink.h" using namespace std; @@ -84,6 +85,9 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); EXPECT_EQ(retVal, 1); + std::string target = FollowSymLink(invalidLink.c_str()); + EXPECT_EQ(target, invalidFile); + unlink(invalidLink.c_str()); } @@ -91,12 +95,18 @@ TEST_F(CreateSymLinkTest, SymLinkToFile) { int retVal = IsSymLink(fileSymLink.c_str()); EXPECT_EQ(1, retVal); + + std::string target = FollowSymLink(fileSymLink.c_str()); + EXPECT_EQ(target, file); } TEST_F(CreateSymLinkTest, SymLinkToDirectory) { int retVal = IsSymLink(dirSymLink.c_str()); EXPECT_EQ(1, retVal); + + std::string target = FollowSymLink(dirSymLink.c_str()); + EXPECT_EQ(target, dir); } TEST_F(CreateSymLinkTest, SymLinkAgain)