new native code and test for obtaining target of symlinks

This commit is contained in:
George Fleming 2016-03-25 14:37:16 -07:00
parent 86801f0457
commit 454524cf72
4 changed files with 113 additions and 3 deletions

View File

@ -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})

90
src/followsymlink.cpp Normal file
View File

@ -0,0 +1,90 @@
//! @file followSymLink.cpp
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief returns whether a path is a symbolic link
#include <errno.h>
#include <unistd.h>
#include <string>
#include <iostream>
#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);
}

9
src/followsymlink.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "pal.h"
PAL_BEGIN_EXTERNC
char* FollowSymLink(const char* fileName);
PAL_END_EXTERNC

View File

@ -1,12 +1,13 @@
//! @file test-issymlink.cpp
//! @file test-createsymlink.cpp
//! @author George Fleming <v-geflem@microsoft.com>
//! @brief Implements test for isSymLink()
//! @brief Implements test for CreateSymLink() and FollowSymLink()
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#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)