Add GetLStat

faccessat() does not support AT_SYMLINK_NOFOLLOW on OS X, so instead,
we use the success of lstat() to determine if the file (not following
symbolic links) exists. Also allowed for some refactoring.
This commit is contained in:
Andrew Schwartzmeyer
2016-07-14 19:45:14 -07:00
parent 70aa6af960
commit ed39a00f29
7 changed files with 115 additions and 43 deletions
+1
View File
@@ -1,5 +1,6 @@
add_library(psl-native SHARED
getstat.cpp
getlstat.cpp
getpwuid.cpp
getuserfrompid.cpp
getfileowner.cpp
+95
View File
@@ -0,0 +1,95 @@
//! @file getlstat.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the lstat of a file
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "getlstat.h"
//! @brief GetLStat returns the lstat of a file. This simply delegates to the
//! lstat() system call and maps errno to the expected values for GetLastError.
//!
//! GetLstat
//!
//! @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] lstat
//! @parblock
//! A pointer to the buffer in which to place the lstat information
//! @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 kernel memory
//!
//! @retval 0 if successful
//! @retval -1 if failed
//!
int32_t GetLStat(const char* path, struct stat* buf)
{
errno = 0;
if (!path)
{
errno = ERROR_INVALID_PARAMETER;
return -1;
}
int32_t ret = lstat(path, buf);
if (ret != 0)
{
switch(errno)
{
case EACCES:
errno = ERROR_ACCESS_DENIED;
break;
case EBADF:
errno = ERROR_FILE_NOT_FOUND;
break;
case EFAULT:
errno = ERROR_INVALID_ADDRESS;
break;
case ELOOP:
errno = ERROR_STOPPED_ON_SYMLINK;
break;
case ENAMETOOLONG:
errno = ERROR_GEN_FAILURE;
break;
case ENOENT:
errno = ERROR_FILE_NOT_FOUND;
break;
case ENOMEM:
errno = ERROR_NO_SUCH_USER;
break;
case ENOTDIR:
errno = ERROR_INVALID_NAME;
break;
case EOVERFLOW:
errno = ERROR_BUFFER_OVERFLOW;
break;
default:
errno = ERROR_INVALID_FUNCTION;
}
}
return ret;
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <sys/stat.h>
#include "pal.h"
PAL_BEGIN_EXTERNC
int32_t GetLStat(const char* path, struct stat* buf);
PAL_END_EXTERNC
+1 -2
View File
@@ -89,8 +89,7 @@ int32_t GetStat(const char* path, struct stat* buf)
default:
errno = ERROR_INVALID_FUNCTION;
}
return -1;
}
return 0;
return ret;
}
+1 -2
View File
@@ -31,7 +31,6 @@
//!
bool IsDirectory(const char* path)
{
int32_t ret = 0;
errno = 0;
if (!path)
@@ -41,7 +40,7 @@ bool IsDirectory(const char* path)
}
struct stat buf;
ret = GetStat(path, &buf);
int32_t ret = GetStat(path, &buf);
if (ret != 0)
{
return false;
+3 -2
View File
@@ -9,6 +9,7 @@
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "getlstat.h"
#include "isfile.h"
//! @brief returns if the path is a file or directory
@@ -37,6 +38,6 @@ bool IsFile(const char* path)
return false;
}
// Resolve relative paths to cwd of process, and do not follow symlinks
return faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW) != -1;
struct stat buf;
return GetLStat(path, &buf) == 0;
}
+4 -37
View File
@@ -7,6 +7,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include "getlstat.h"
#include "issymlink.h"
//! @brief IsSymlink determines if path is a symbolic link
@@ -48,46 +49,12 @@ bool IsSymLink(const char* path)
return false;
}
struct stat statBuf;
int ret = lstat(path, &statBuf);
struct stat buf;
int32_t ret = GetLStat(path, &buf);
if (ret != 0)
{
switch(errno)
{
case EACCES:
errno = ERROR_ACCESS_DENIED;
break;
case EBADF:
errno = ERROR_FILE_NOT_FOUND;
break;
case EFAULT:
errno = ERROR_INVALID_ADDRESS;
break;
case ELOOP:
errno = ERROR_STOPPED_ON_SYMLINK;
break;
case ENAMETOOLONG:
errno = ERROR_GEN_FAILURE;
break;
case ENOENT:
errno = ERROR_FILE_NOT_FOUND;
break;
case ENOMEM:
errno = ERROR_NO_SUCH_USER;
break;
case ENOTDIR:
errno = ERROR_INVALID_NAME;
break;
case EOVERFLOW:
errno = ERROR_BUFFER_OVERFLOW;
break;
default:
errno = ERROR_INVALID_FUNCTION;
}
return false;
}
return S_ISLNK(statBuf.st_mode);
return S_ISLNK(buf.st_mode);
}