diff --git a/build.psm1 b/build.psm1 index d08d6d3..5319c0d 100644 --- a/build.psm1 +++ b/build.psm1 @@ -439,6 +439,19 @@ function Start-BuildNativeUnixBinaries { git clean -qfdX $Native + # the stat tests rely on stat(1). On most platforms, this is /usr/bin/stat, + # but on alpine it is in /bin. Be sure that /usr/bin/stat exists, or + # create a link from /bin/stat. If /bin/stat is missing, we'll have to fail the build + + if ( ! (Test-Path /usr/bin/stat) ) { + if ( Test-Path /bin/stat ) { + New-Item -Type SymbolicLink -Path /usr/bin/stat -Target /bin/stat + } + else { + throw "Cannot create symlink to stat(1)" + } + } + try { Push-Location $Native if ($BuildLinuxArm) { @@ -1927,7 +1940,7 @@ function Start-PSBootstrap { # Install ours and .NET's dependencies $Deps = @() - if ($Environment.IsUbuntu) { + if ($Environment.IsUbuntu -or $Environment.IsDebian) { # Build tools $Deps += "curl", "g++", "cmake", "make" @@ -1985,7 +1998,8 @@ function Start-PSBootstrap { } } elseif ($Environment.IsSUSEFamily) { # Build tools - $Deps += "gcc", "cmake", "make" + # we're using a flag which requires an up to date compiler + $Deps += "gcc7", "cmake", "make", "gcc7-c++" # Packaging tools if ($Package) { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel' } @@ -2003,6 +2017,21 @@ function Start-PSBootstrap { Start-NativeExecution { Invoke-Expression "$baseCommand $Deps" } + + # After installation, create the appropriate symbolic links + foreach ($compiler in "gcc-7","g++-7") { + $itemPath = "/usr/bin/${compiler}" + $name = $compiler -replace "-7" + $linkPath = "/usr/bin/${name}" + $link = Get-Item -Path $linkPath -ErrorAction SilentlyContinue + if ($link) { + if ($link.Target) { # Symbolic link - remove it + Remove-Item -Force -Path $linkPath + } + } + New-Item -Type SymbolicLink -Target $itemPath -Path $linkPath + } + } elseif ($Environment.IsMacOS) { precheck 'brew' "Bootstrap dependency 'brew' not found, must install Homebrew! See http://brew.sh/" diff --git a/src/libpsl-native/gmock.pc b/src/libpsl-native/gmock.pc new file mode 100644 index 0000000..dd45b5f --- /dev/null +++ b/src/libpsl-native/gmock.pc @@ -0,0 +1,9 @@ +libdir=/usr/local/lib +includedir=/usr/local/include + +Name: gmock +Description: GoogleMock (without main() function) +Version: 1.9.0 +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgmock +Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 diff --git a/src/libpsl-native/gmock_main.pc b/src/libpsl-native/gmock_main.pc new file mode 100644 index 0000000..ad1e97b --- /dev/null +++ b/src/libpsl-native/gmock_main.pc @@ -0,0 +1,9 @@ +libdir=/usr/local/lib +includedir=/usr/local/include + +Name: gmock_main +Description: GoogleMock (with main() function) +Version: 1.9.0 +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgmock_main +Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 diff --git a/src/libpsl-native/gtest.pc b/src/libpsl-native/gtest.pc new file mode 100644 index 0000000..c7c84e6 --- /dev/null +++ b/src/libpsl-native/gtest.pc @@ -0,0 +1,9 @@ +libdir=/usr/local/lib +includedir=/usr/local/include + +Name: gtest +Description: GoogleTest (without main() function) +Version: 1.9.0 +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgtest +Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 diff --git a/src/libpsl-native/gtest_main.pc b/src/libpsl-native/gtest_main.pc new file mode 100644 index 0000000..4c5d885 --- /dev/null +++ b/src/libpsl-native/gtest_main.pc @@ -0,0 +1,10 @@ +libdir=/usr/local/lib +includedir=/usr/local/include + +Name: gtest_main +Description: GoogleTest (with main() function) +Version: 1.9.0 +URL: https://github.com/google/googletest +Requires: gtest +Libs: -L${libdir} -lgtest_main +Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 889ba7b..3b06458 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -2,7 +2,11 @@ include(CheckIncludeFiles) add_library(psl-native SHARED getstat.cpp + getlstat.cpp + getcommonstat.cpp + getcommonlstat.cpp getpwuid.cpp + getgrgid.cpp getppid.cpp getuserfrompid.cpp getfileowner.cpp diff --git a/src/libpsl-native/src/getcommonlstat.cpp b/src/libpsl-native/src/getcommonlstat.cpp new file mode 100644 index 0000000..3aa878d --- /dev/null +++ b/src/libpsl-native/src/getcommonlstat.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief returns the stat of a file + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "getcommonlstat.h" + +// Provide a common structure for the various different stat structures. +// This should be safe to call on all platforms +int GetCommonLStat(const char* path, struct CommonStat* commonStat) +{ + struct stat st; + assert(path); + errno = 0; + if (lstat(path, &st) == 0) + { + commonStat->Inode = st.st_ino; + commonStat->Mode = st.st_mode; + commonStat->UserId = st.st_uid; + commonStat->GroupId = st.st_gid; + commonStat->HardlinkCount = st.st_nlink; + commonStat->Size = st.st_size; +#if defined (__APPLE__) + commonStat->AccessTime = st.st_atimespec.tv_sec; + commonStat->ModifiedTime = st.st_mtimespec.tv_sec; + commonStat->ChangeTime = st.st_ctimespec.tv_sec; +#else + commonStat->AccessTime = st.st_atime; + commonStat->ModifiedTime = st.st_mtime; + commonStat->ChangeTime = st.st_ctime; +#endif + commonStat->BlockSize = st.st_blksize; + commonStat->DeviceId = st.st_dev; + commonStat->NumberOfBlocks = st.st_blocks; + commonStat->IsBlockDevice = S_ISBLK(st.st_mode); + commonStat->IsCharacterDevice = S_ISCHR(st.st_mode); + commonStat->IsDirectory = S_ISDIR(st.st_mode); + commonStat->IsFile = S_ISREG(st.st_mode); + commonStat->IsNamedPipe = S_ISFIFO(st.st_mode); + commonStat->IsSocket = S_ISSOCK(st.st_mode); + commonStat->IsSymbolicLink = S_ISLNK(st.st_mode); + commonStat->IsSetUid = (st.st_mode & 0xE00) == S_ISUID; + commonStat->IsSetGid = (st.st_mode & 0xE00) == S_ISGID; + commonStat->IsSticky = (st.st_mode & 0xE00) == S_ISVTX; + return 0; + } + return -1; +} + diff --git a/src/libpsl-native/src/getcommonlstat.h b/src/libpsl-native/src/getcommonlstat.h new file mode 100644 index 0000000..dc2aaba --- /dev/null +++ b/src/libpsl-native/src/getcommonlstat.h @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pal.h" + +#include + +#include "getcommonstat.h" + +PAL_BEGIN_EXTERNC + +int32_t GetLStat(const char* path, struct stat* buf); +int GetCommonLStat(const char* path, CommonStat* cs); + +PAL_END_EXTERNC + diff --git a/src/libpsl-native/src/getcommonstat.cpp b/src/libpsl-native/src/getcommonstat.cpp new file mode 100644 index 0000000..53b50c2 --- /dev/null +++ b/src/libpsl-native/src/getcommonstat.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief returns the stat of a file + +#include "getcommonstat.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +// Provide a common structure for the various different stat structures. +// This should be safe to call on all platforms +int GetCommonStat(const char* path, struct CommonStat* commonStat) +{ + struct stat st; + assert(path); + errno = 0; + if (stat(path, &st) == 0) + { + commonStat->Inode = st.st_ino; + commonStat->Mode = st.st_mode; + commonStat->UserId = st.st_uid; + commonStat->GroupId = st.st_gid; + commonStat->HardlinkCount = st.st_nlink; + commonStat->Size = st.st_size; +#if defined (__APPLE__) + commonStat->AccessTime = st.st_atimespec.tv_sec; + commonStat->ModifiedTime = st.st_mtimespec.tv_sec; + commonStat->ChangeTime = st.st_ctimespec.tv_sec; +#else + commonStat->AccessTime = st.st_atime; + commonStat->ModifiedTime = st.st_mtime; + commonStat->ChangeTime = st.st_ctime; +#endif + commonStat->BlockSize = st.st_blksize; + commonStat->DeviceId = st.st_dev; + commonStat->NumberOfBlocks = st.st_blocks; + commonStat->IsBlockDevice = S_ISBLK(st.st_mode); + commonStat->IsCharacterDevice = S_ISCHR(st.st_mode); + commonStat->IsDirectory = S_ISDIR(st.st_mode); + commonStat->IsFile = S_ISREG(st.st_mode); + commonStat->IsNamedPipe = S_ISFIFO(st.st_mode); + commonStat->IsSocket = S_ISSOCK(st.st_mode); + commonStat->IsSymbolicLink = S_ISLNK(st.st_mode); + commonStat->IsSetUid = (st.st_mode & 0xE00) == S_ISUID; + commonStat->IsSetGid = (st.st_mode & 0xE00) == S_ISGID; + commonStat->IsSticky = (st.st_mode & 0xE00) == S_ISVTX; + return 0; + } + return -1; +} + diff --git a/src/libpsl-native/src/getcommonstat.h b/src/libpsl-native/src/getcommonstat.h new file mode 100644 index 0000000..9fd9f40 --- /dev/null +++ b/src/libpsl-native/src/getcommonstat.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pal.h" + +#include + +PAL_BEGIN_EXTERNC + +struct CommonStat +{ + long Inode; + int Mode; + int UserId; + int GroupId; + int HardlinkCount; + long Size; + long AccessTime; + long ModifiedTime; + long ChangeTime; + long BlockSize; + int DeviceId; + int NumberOfBlocks; + int IsDirectory; + int IsFile; + int IsSymbolicLink; + int IsBlockDevice; + int IsCharacterDevice; + int IsNamedPipe; + int IsSocket; + int IsSetUid; + int IsSetGid; + int IsSticky; +}; + +int32_t GetStat(const char* path, struct stat* buf); +int GetCommonStat(const char* path, CommonStat* cs); + +PAL_END_EXTERNC + diff --git a/src/libpsl-native/src/getgrgid.cpp b/src/libpsl-native/src/getgrgid.cpp new file mode 100644 index 0000000..27329ae --- /dev/null +++ b/src/libpsl-native/src/getgrgid.cpp @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief returns the groupname for a gid + +#include "getgrgid.h" + +#include +#include +#include +#include +#include +#include + +//! @brief GetGrGid returns the groupname for a gid +//! +//! GetGrGid +//! +//! @param[in] gid +//! @parblock +//! The group identifier to lookup. +//! @endparblock +//! +//! @retval groupname as UTF-8 string, or NULL if unsuccessful +//! +char* GetGrGid(gid_t gid) +{ + int32_t ret = 0; + struct group grp; + struct group* result = NULL; + char* buf; + + int buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen < 1) + { + buflen = 2048; + } + +allocate: + buf = (char*)calloc(buflen, sizeof(char)); + + errno = 0; + ret = getgrgid_r(gid, &grp, buf, buflen, &result); + + if (ret != 0) + { + if (errno == ERANGE) + { + free(buf); + buflen *= 2; + goto allocate; + } + return NULL; + } + + // no group found + if (result == NULL) + { + return NULL; + } + + // allocate copy on heap so CLR can free it + size_t userlen = strnlen(grp.gr_name, buflen); + char* groupname = strndup(grp.gr_name, userlen); + free(buf); + return groupname; +} + diff --git a/src/libpsl-native/src/getgrgid.h b/src/libpsl-native/src/getgrgid.h new file mode 100644 index 0000000..a2aaa30 --- /dev/null +++ b/src/libpsl-native/src/getgrgid.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pal.h" + +#include + +PAL_BEGIN_EXTERNC + +char* GetGrGid(gid_t gid); + +PAL_END_EXTERNC + diff --git a/src/libpsl-native/src/getlstat.cpp b/src/libpsl-native/src/getlstat.cpp new file mode 100644 index 0000000..0517851 --- /dev/null +++ b/src/libpsl-native/src/getlstat.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief returns the stat of a file + +#include "getlstat.h" + +#include +#include +#include +#include +#include +#include +#include + +//! @brief GetStat returns the stat of a file. This simply delegates to the +//! stat() system call and maps errno to the expected values for GetLastError. +//! +//! GetStat +//! +//! @param[in] path +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @param[in] stat +//! @parblock +//! A pointer to the buffer in which to place the stat information +//! @endparblock +//! +//! @retval 0 if successful +//! @retval -1 if failed +//! + +// DO NOT use in managed code +// use externally defined structs in managed code has proven to be buggy +// (memory corruption issues due to layout difference between platforms) +// see https://github.com/dotnet/corefx/issues/29700#issuecomment-389313075 +int32_t GetLStat(const char* path, struct stat* buf) +{ + assert(path); + errno = 0; + + return lstat(path, buf); +} + diff --git a/src/libpsl-native/src/getlstat.h b/src/libpsl-native/src/getlstat.h new file mode 100644 index 0000000..7ebe280 --- /dev/null +++ b/src/libpsl-native/src/getlstat.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pal.h" + +#include + +PAL_BEGIN_EXTERNC + +int32_t GetLStat(const char* path, struct stat* buf); + +PAL_END_EXTERNC + diff --git a/src/libpsl-native/src/getstat.cpp b/src/libpsl-native/src/getstat.cpp index 2cc6f66..8120e22 100644 --- a/src/libpsl-native/src/getstat.cpp +++ b/src/libpsl-native/src/getstat.cpp @@ -45,3 +45,4 @@ int32_t GetStat(const char* path, struct stat* buf) return stat(path, buf); } + diff --git a/src/libpsl-native/src/isdirectory.cpp b/src/libpsl-native/src/isdirectory.cpp index 1123dc5..5afd2b6 100644 --- a/src/libpsl-native/src/isdirectory.cpp +++ b/src/libpsl-native/src/isdirectory.cpp @@ -15,6 +15,8 @@ #include #include +#include + //! @brief returns if the path is a directory; uses stat and so follows symlinks //! //! IsDirectory @@ -41,3 +43,4 @@ bool IsDirectory(const char* path) return S_ISDIR(buf.st_mode); } + diff --git a/src/libpsl-native/test/CMakeLists.txt b/src/libpsl-native/test/CMakeLists.txt index eb496e0..9d3f4f5 100644 --- a/src/libpsl-native/test/CMakeLists.txt +++ b/src/libpsl-native/test/CMakeLists.txt @@ -6,7 +6,11 @@ add_executable(psl-native-test test-getuserfrompid.cpp test-getcurrentprocessid.cpp test-getcomputername.cpp + test-getcommonstat.cpp + test-getcommonlstat.cpp test-getlinkcount.cpp + test-getgrgid.cpp + test-getpwuid.cpp test-isdirectory.cpp test-isfile.cpp test-issymlink.cpp diff --git a/src/libpsl-native/test/test-getcommonlstat.cpp b/src/libpsl-native/test/test-getcommonlstat.cpp new file mode 100644 index 0000000..fca9890 --- /dev/null +++ b/src/libpsl-native/test/test-getcommonlstat.cpp @@ -0,0 +1,292 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief Tests IsDirectory + +#include +#include +#include +#include "isdirectory.h" +#include "getcommonlstat.h" + +TEST(GetCommonLStat, RootIsDirectory) +{ + CommonStat cs; + GetCommonLStat("/", &cs); + bool isDir = IsDirectory("/"); + bool fromCommonLStat = (bool)cs.IsDirectory; + EXPECT_EQ(isDir, fromCommonLStat); +} + +TEST(GetCommonLStat, BinLsIsNotDirectory) +{ + CommonStat cs; + GetCommonLStat("/bin/ls", &cs); + bool isDir = IsDirectory("/bin/ls"); + bool fromCommonLStat = (bool)cs.IsDirectory; + EXPECT_EQ(isDir, fromCommonLStat); +} + + +TEST(GetCommonLStat, ReturnsFalseForFakeDirectory) +{ + CommonStat cs; + int badDir = GetCommonLStat("/A/Really/Bad/Directory",&cs); + EXPECT_EQ(badDir, -1); +} + +TEST(GetCommonLStat, GetOwnerIdOfRoot) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %u /", "r"); +#else + p = popen("/usr/bin/stat -c %u /", "r"); +#endif + int uid = -1; + int result = fscanf(p, "%d", &uid); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(uid, cs.UserId); +} + +TEST(GetCommonLStat, GetGroupId) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %g /", "r"); +#else + p = popen("/usr/bin/stat -c %g /", "r"); +#endif + int gid = -1; + int result = fscanf(p, "%d", &gid); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(gid, cs.GroupId); +} + +TEST(GetCommonLStat, GetInodeNumber) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %i /", "r"); +#else + p = popen("/usr/bin/stat -c %i /", "r"); +#endif + long inode = -1; + int result = fscanf(p, "%ld", &inode); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(inode, cs.Inode); +} + +TEST(GetCommonLStat, GetSize) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %z /", "r"); +#else + p = popen("/usr/bin/stat -c %s /", "r"); +#endif + long size = -1; + int result = fscanf(p, "%ld", &size); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(size, cs.Size); +} + +TEST(GetCommonLStat, GetBlockSize) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %k /", "r"); +#else + p = popen("/usr/bin/stat -c %o /", "r"); +#endif + long bSize = -1; + int result = fscanf(p, "%ld", &bSize); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(bSize, cs.BlockSize); +} + +TEST(GetCommonLStat, GetBlockCount) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %b /", "r"); +#else + p = popen("/usr/bin/stat -c %b /", "r"); +#endif + int bSize = -1; + int result = fscanf(p, "%d", &bSize); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(bSize, cs.NumberOfBlocks); +} + +TEST(GetCommonLStat, GetLinkCount) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %l /", "r"); +#else + p = popen("/usr/bin/stat -c %h /", "r"); +#endif + int linkcount = -1; + int result = fscanf(p, "%d", &linkcount); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(linkcount, cs.HardlinkCount); +} + +TEST(GetCommonLStat, GetDeviceId) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %d /", "r"); +#else + p = popen("/usr/bin/stat -c %d /", "r"); +#endif + int deviceId = -1; + int result = fscanf(p, "%d", &deviceId); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(deviceId, cs.DeviceId); +} + +TEST(GetCommonLStat, GetATime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %a /", "r"); +#else + p = popen("/usr/bin/stat -c %X /", "r"); +#endif + long aTime = -1; + int result = fscanf(p, "%ld", &aTime); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(aTime, cs.AccessTime); +} + +TEST(GetCommonLStat, GetMTime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %m /", "r"); +#else + p = popen("/usr/bin/stat -c %Y /", "r"); +#endif + long mTime = -1; + int result = fscanf(p, "%ld", &mTime); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(mTime, cs.ModifiedTime); +} + +TEST(GetCommonLStat, GetCTime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %c /", "r"); +#else + p = popen("/usr/bin/stat -c %Z /", "r"); +#endif + long cTime = -1; + int result = fscanf(p, "%ld", &cTime); + pclose(p); + GetCommonLStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(cTime, cs.ChangeTime); +} + +TEST(GetCommonLStat, Mode001) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH); + lstat(fname, &buffer); + GetCommonLStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonLStat, Mode002) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH | S_ISUID ); + lstat(fname, &buffer); + GetCommonLStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonLStat, Mode003) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_ISGID ); + lstat(fname, &buffer); + GetCommonLStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonLStat, Mode004) +{ + const std::string ftemplate = "/tmp/CommonStatModeD_XXXXXX"; + char dname[PATH_MAX]; + struct stat buffer; + char * fd; + CommonStat cs; + strcpy(dname, ftemplate.c_str()); + fd = mkdtemp(dname); + EXPECT_NE(fd, ftemplate); + chmod(dname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH | S_ISVTX ); + lstat(dname, &buffer); + GetCommonLStat(dname, &cs); + rmdir(dname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + diff --git a/src/libpsl-native/test/test-getcommonstat.cpp b/src/libpsl-native/test/test-getcommonstat.cpp new file mode 100644 index 0000000..1df6a3d --- /dev/null +++ b/src/libpsl-native/test/test-getcommonstat.cpp @@ -0,0 +1,312 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief Tests IsDirectory + +#include +#include +#include +#include "isdirectory.h" +#include "getcommonstat.h" +#include +#include + +TEST(GetCommonStat, RootIsDirectory) +{ + CommonStat cs; + GetCommonStat("/", &cs); + bool isDir = IsDirectory("/"); + bool fromCommonStat = (bool)cs.IsDirectory; + EXPECT_EQ(isDir, fromCommonStat); +} + +TEST(GetCommonStat, BinLsIsNotDirectory) +{ + CommonStat cs; + GetCommonStat("/bin/ls", &cs); + bool isDir = IsDirectory("/bin/ls"); + bool fromCommonStat = (bool)cs.IsDirectory; + EXPECT_EQ(isDir, fromCommonStat); +} + + +TEST(GetCommonStat, ReturnsFalseForFakeDirectory) +{ + CommonStat cs; + int badDir = GetCommonStat("/A/Really/Bad/Directory",&cs); + EXPECT_EQ(badDir, -1); +} + +TEST(GetCommonStat, GetOwnerIdOfRoot) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %u /", "r"); +#else + p = popen("/usr/bin/stat -c %u /", "r"); +#endif + int uid = -1; + int result = fscanf(p, "%d", &uid); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(uid, cs.UserId); +} + +TEST(GetCommonStat, GetGroupId) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %g /", "r"); +#else + p = popen("/usr/bin/stat -c %g /", "r"); +#endif + int gid = -1; + int result = fscanf(p, "%d", &gid); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(gid, cs.GroupId); +} + +TEST(GetCommonStat, GetInodeNumber) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %i /", "r"); +#else + p = popen("/usr/bin/stat -c %i /", "r"); +#endif + long inode = -1; + int result = fscanf(p, "%ld", &inode); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(inode, cs.Inode); +} + +TEST(GetCommonStat, GetMode) +{ + FILE *p; + CommonStat cs; + unsigned int mode = -1; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %p /", "r"); + int result = fscanf(p, "%o", &mode); +#else + p = popen("/usr/bin/stat -c %f /", "r"); + int result = fscanf(p, "%x", &mode); +#endif + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(mode, cs.Mode); +} + +TEST(GetCommonStat, GetSize) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %z /", "r"); +#else + p = popen("/usr/bin/stat -c %s /", "r"); +#endif + long size = -1; + int result = fscanf(p, "%ld", &size); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(size, cs.Size); +} + +TEST(GetCommonStat, GetBlockSize) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %k /", "r"); +#else + p = popen("/usr/bin/stat -c %o /", "r"); +#endif + long bSize = -1; + int result = fscanf(p, "%ld", &bSize); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(bSize, cs.BlockSize); +} + +TEST(GetCommonStat, GetBlockCount) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %b /", "r"); +#else + p = popen("/usr/bin/stat -c %b /", "r"); +#endif + int bSize = -1; + int result = fscanf(p, "%d", &bSize); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(bSize, cs.NumberOfBlocks); +} + +TEST(GetCommonStat, GetLinkCount) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %l /", "r"); +#else + p = popen("/usr/bin/stat -c %h /", "r"); +#endif + int linkcount = -1; + int result = fscanf(p, "%d", &linkcount); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(linkcount, cs.HardlinkCount); +} + +TEST(GetCommonStat, GetDeviceId) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %d /", "r"); +#else + p = popen("/usr/bin/stat -c %d /", "r"); +#endif + int deviceId = -1; + int result = fscanf(p, "%d", &deviceId); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(deviceId, cs.DeviceId); +} + +TEST(GetCommonStat, GetATime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %a /", "r"); +#else + p = popen("/usr/bin/stat -c %X /", "r"); +#endif + long aTime = -1; + int result = fscanf(p, "%ld", &aTime); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(aTime, cs.AccessTime); +} + +TEST(GetCommonStat, GetMTime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %m /", "r"); +#else + p = popen("/usr/bin/stat -c %Y /", "r"); +#endif + long mTime = -1; + int result = fscanf(p, "%ld", &mTime); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(mTime, cs.ModifiedTime); +} + +TEST(GetCommonStat, GetCTime) +{ + FILE *p; + CommonStat cs; +#if defined (__APPLE__) + p = popen("/usr/bin/stat -f %c /", "r"); +#else + p = popen("/usr/bin/stat -c %Z /", "r"); +#endif + long cTime = -1; + int result = fscanf(p, "%ld", &cTime); + pclose(p); + GetCommonStat("/", &cs); + EXPECT_EQ(result, 1); + EXPECT_EQ(cTime, cs.ChangeTime); +} + +TEST(GetCommonStat, Mode001) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH); + stat(fname, &buffer); + GetCommonStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonStat, Mode002) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH | S_ISUID ); + stat(fname, &buffer); + GetCommonStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonStat, Mode003) +{ + const std::string ftemplate = "/tmp/CommonStatModeF_XXXXXX"; + char fname[PATH_MAX]; + struct stat buffer; + int fd; + CommonStat cs; + strcpy(fname, ftemplate.c_str()); + fd = mkstemp(fname); + EXPECT_NE(fd, -1); + chmod(fname, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_ISGID ); + stat(fname, &buffer); + GetCommonStat(fname, &cs); + unlink(fname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + +TEST(GetCommonStat, Mode004) +{ + const std::string ftemplate = "/tmp/CommonStatModeD_XXXXXX"; + char dname[PATH_MAX]; + struct stat buffer; + char * fd; + CommonStat cs; + strcpy(dname, ftemplate.c_str()); + fd = mkdtemp(dname); + EXPECT_NE(fd, ftemplate); + chmod(dname, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH | S_ISVTX ); + stat(dname, &buffer); + GetCommonStat(dname, &cs); + rmdir(dname); + EXPECT_EQ(cs.Mode, buffer.st_mode); +} + diff --git a/src/libpsl-native/test/test-getgrgid.cpp b/src/libpsl-native/test/test-getgrgid.cpp new file mode 100644 index 0000000..017dd1c --- /dev/null +++ b/src/libpsl-native/test/test-getgrgid.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief Unit tests for GetUserFromPid + +#include +#include +#include "getgrgid.h" + +TEST(GetGrGid, Success) +{ + char* expected = getgrgid(getegid())->gr_name; + EXPECT_STREQ(GetGrGid(getegid()), expected); +} + diff --git a/src/libpsl-native/test/test-getlinkcount.cpp b/src/libpsl-native/test/test-getlinkcount.cpp index 741c0c5..d9c388f 100644 --- a/src/libpsl-native/test/test-getlinkcount.cpp +++ b/src/libpsl-native/test/test-getlinkcount.cpp @@ -33,6 +33,11 @@ class getLinkCountTest : public ::testing::Test file = fileTemplateBuf; } + ~getLinkCountTest() + { + unlink(fileTemplateBuf); + } + void createFileForTesting(const std::string &theFile) { std::ofstream ofs; @@ -69,10 +74,12 @@ TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile) { createFileForTesting(file); int32_t ret = GetLinkCount(file, &count); + + removeFile(file); + ASSERT_EQ(0, ret); EXPECT_EQ(1, count); - removeFile(file); } TEST_F(getLinkCountTest, LinkCountOfMultiplyLinkedFile) @@ -80,10 +87,12 @@ TEST_F(getLinkCountTest, LinkCountOfMultiplyLinkedFile) createFileForTesting(file); std::string newFile = createHardLink(file); int32_t ret = GetLinkCount(file, &count); - ASSERT_EQ(0, ret); - EXPECT_EQ(2, count); removeFile(file); removeFile(newFile); + + ASSERT_EQ(0, ret); + EXPECT_EQ(2, count); + } diff --git a/src/libpsl-native/test/test-getpwuid.cpp b/src/libpsl-native/test/test-getpwuid.cpp new file mode 100644 index 0000000..563eff8 --- /dev/null +++ b/src/libpsl-native/test/test-getpwuid.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//! @brief Unit tests for GetUserFromPid + +#include +#include +#include "getpwuid.h" + +TEST(GetPwUid, Success) +{ + char* expected = getpwuid(geteuid())->pw_name; + EXPECT_STREQ(GetPwUid(geteuid()), expected); +} +