Skip to content

Commit

Permalink
[Support] Implement is_local_impl with AIX mntctl
Browse files Browse the repository at this point in the history
Summary:
On AIX, we can determine whether a filesystem is remote using `mntctl`.

If the information is not found, then claim that the file is remote
(since that is the more restrictive case). Testing for the associated
interface is restored with a modified version of the unit test from
rL295768.

Reviewers: jasonliu, xingxue

Reviewed By: xingxue

Subscribers: jsji, apaprocki, Hahnfeld, zturner, krytarowski, kristina, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D58801

llvm-svn: 357333
  • Loading branch information
hubert-reinterpretcast committed Mar 29, 2019
1 parent 4d6fb57 commit 2416885
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
48 changes: 45 additions & 3 deletions llvm/lib/Support/Unix/Path.inc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

#include <sys/types.h>
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \
!defined(__linux__) && !defined(__FreeBSD_kernel__)
!defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX)
#include <sys/statvfs.h>
#define STATVFS statvfs
#define FSTATVFS fstatvfs
Expand All @@ -76,6 +76,14 @@
#endif
#endif
#include <sys/vfs.h>
#elif defined(_AIX)
#include <sys/statfs.h>

// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
// the typedef prior to including <sys/vmount.h> to work around this issue.
typedef uint_t uint;
#include <sys/vmount.h>
#else
#include <sys/mount.h>
#endif
Expand Down Expand Up @@ -249,7 +257,7 @@ uint32_t file_status::getLinkCount() const {

ErrorOr<space_info> disk_space(const Twine &Path) {
struct STATVFS Vfs;
if (::STATVFS(Path.str().c_str(), &Vfs))
if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
return std::error_code(errno, std::generic_category());
auto FrSize = STATVFS_F_FRSIZE(Vfs);
space_info SpaceInfo;
Expand Down Expand Up @@ -409,14 +417,48 @@ static bool is_local_impl(struct STATVFS &Vfs) {
StringRef fstype(Vfs.f_basetype);
// NFS is the only non-local fstype??
return !fstype.equals("nfs");
#elif defined(_AIX)
// Call mntctl; try more than twice in case of timing issues with a concurrent
// mount.
int Ret;
size_t BufSize = 2048u;
std::unique_ptr<char[]> Buf;
int Tries = 3;
while (Tries--) {
Buf = llvm::make_unique<char[]>(BufSize);
Ret = mntctl(MCTL_QUERY, BufSize, Buf.get());
if (Ret != 0)
break;
BufSize = *reinterpret_cast<unsigned int *>(Buf.get());
Buf.reset();
}

if (Ret == -1)
// There was an error; "remote" is the conservative answer.
return false;

// Look for the correct vmount entry.
char *CurObjPtr = Buf.get();
while (Ret--) {
struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr);
static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid),
"fsid length mismatch");
if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0)
return (Vp->vmt_flags & MNT_REMOTE) == 0;

CurObjPtr += Vp->vmt_length;
}

// vmount entry not found; "remote" is the conservative answer.
return false;
#else
return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
#endif
}

std::error_code is_local(const Twine &Path, bool &Result) {
struct STATVFS Vfs;
if (::STATVFS(Path.str().c_str(), &Vfs))
if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
return std::error_code(errno, std::generic_category());

Result = is_local_impl(Vfs);
Expand Down
23 changes: 23 additions & 0 deletions llvm/unittests/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,29 @@ TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) {
verifyWrite(FD, "Buzz", true);
}

TEST_F(FileSystemTest, is_local) {
bool TestDirectoryIsLocal;
ASSERT_NO_ERROR(fs::is_local(TestDirectory, TestDirectoryIsLocal));
EXPECT_EQ(TestDirectoryIsLocal, fs::is_local(TestDirectory));

int FD;
SmallString<128> TempPath;
ASSERT_NO_ERROR(
fs::createUniqueFile(Twine(TestDirectory) + "/temp", FD, TempPath));
FileRemover Cleanup(TempPath);

// Make sure it exists.
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));

bool TempFileIsLocal;
ASSERT_NO_ERROR(fs::is_local(FD, TempFileIsLocal));
EXPECT_EQ(TempFileIsLocal, fs::is_local(FD));

// Expect that the file and its parent directory are equally local or equally
// remote.
EXPECT_EQ(TestDirectoryIsLocal, TempFileIsLocal);
}

TEST_F(FileSystemTest, set_current_path) {
SmallString<128> path;

Expand Down

0 comments on commit 2416885

Please sign in to comment.