Skip to content

Add a number of native calls to prepare for stat in PowerShell #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions build.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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' }
Expand All @@ -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/"

Expand Down
9 changes: 9 additions & 0 deletions src/libpsl-native/gmock.pc
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions src/libpsl-native/gmock_main.pc
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions src/libpsl-native/gtest.pc
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions src/libpsl-native/gtest_main.pc
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions src/libpsl-native/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions src/libpsl-native/src/getcommonlstat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

//! @brief returns the stat of a file

#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>

#include <stdio.h>

#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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is difficult to see a difference GetCommonLStat vs GetCommonStat. Also name of returned struct CommonStat says all we want. I see short names GetLStat and GetStat is used already. We could use name like GetStatC or even one common name with the third bool parameter UseSymbolicLink - in last case we will have only single P/Invoke entry in C#.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in this project, all the APIs have a 1 to 1 mapping with the native APIs, we should have two APIs namely GetCommonStat -> stat and GetCommonLStat -> lstat

{
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;
}

18 changes: 18 additions & 0 deletions src/libpsl-native/src/getcommonlstat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include "pal.h"

#include <sys/stat.h>

#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

59 changes: 59 additions & 0 deletions src/libpsl-native/src/getcommonstat.cpp
Original file line number Diff line number Diff line change
@@ -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 <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>

#include <stdio.h>

// 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;
}

42 changes: 42 additions & 0 deletions src/libpsl-native/src/getcommonstat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include "pal.h"

#include <sys/stat.h>

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

68 changes: 68 additions & 0 deletions src/libpsl-native/src/getgrgid.cpp
Original file line number Diff line number Diff line change
@@ -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 <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <grp.h>
#include <string.h>
#include <unistd.h>

//! @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;
}
Comment on lines +47 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a check like buflen < 2048?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are you attempting to do with this check? ERANGE is only returned if the buffer is too small

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upper boundary. Or we can support the buffer without upper limit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should support whatever sysctl says it is. This can be set in the OS, while I don't believe there are any OSs which have larger than this, I don't know.

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;
}

15 changes: 15 additions & 0 deletions src/libpsl-native/src/getgrgid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include "pal.h"

#include <sys/types.h>

PAL_BEGIN_EXTERNC

char* GetGrGid(gid_t gid);

PAL_END_EXTERNC

Loading