Skip to content

Commit 2416885

Browse files
[Support] Implement is_local_impl with AIX mntctl
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
1 parent 4d6fb57 commit 2416885

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

llvm/lib/Support/Unix/Path.inc

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555

5656
#include <sys/types.h>
5757
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \
58-
!defined(__linux__) && !defined(__FreeBSD_kernel__)
58+
!defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX)
5959
#include <sys/statvfs.h>
6060
#define STATVFS statvfs
6161
#define FSTATVFS fstatvfs
@@ -76,6 +76,14 @@
7676
#endif
7777
#endif
7878
#include <sys/vfs.h>
79+
#elif defined(_AIX)
80+
#include <sys/statfs.h>
81+
82+
// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
83+
// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
84+
// the typedef prior to including <sys/vmount.h> to work around this issue.
85+
typedef uint_t uint;
86+
#include <sys/vmount.h>
7987
#else
8088
#include <sys/mount.h>
8189
#endif
@@ -249,7 +257,7 @@ uint32_t file_status::getLinkCount() const {
249257

250258
ErrorOr<space_info> disk_space(const Twine &Path) {
251259
struct STATVFS Vfs;
252-
if (::STATVFS(Path.str().c_str(), &Vfs))
260+
if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
253261
return std::error_code(errno, std::generic_category());
254262
auto FrSize = STATVFS_F_FRSIZE(Vfs);
255263
space_info SpaceInfo;
@@ -409,14 +417,48 @@ static bool is_local_impl(struct STATVFS &Vfs) {
409417
StringRef fstype(Vfs.f_basetype);
410418
// NFS is the only non-local fstype??
411419
return !fstype.equals("nfs");
420+
#elif defined(_AIX)
421+
// Call mntctl; try more than twice in case of timing issues with a concurrent
422+
// mount.
423+
int Ret;
424+
size_t BufSize = 2048u;
425+
std::unique_ptr<char[]> Buf;
426+
int Tries = 3;
427+
while (Tries--) {
428+
Buf = llvm::make_unique<char[]>(BufSize);
429+
Ret = mntctl(MCTL_QUERY, BufSize, Buf.get());
430+
if (Ret != 0)
431+
break;
432+
BufSize = *reinterpret_cast<unsigned int *>(Buf.get());
433+
Buf.reset();
434+
}
435+
436+
if (Ret == -1)
437+
// There was an error; "remote" is the conservative answer.
438+
return false;
439+
440+
// Look for the correct vmount entry.
441+
char *CurObjPtr = Buf.get();
442+
while (Ret--) {
443+
struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr);
444+
static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid),
445+
"fsid length mismatch");
446+
if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0)
447+
return (Vp->vmt_flags & MNT_REMOTE) == 0;
448+
449+
CurObjPtr += Vp->vmt_length;
450+
}
451+
452+
// vmount entry not found; "remote" is the conservative answer.
453+
return false;
412454
#else
413455
return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
414456
#endif
415457
}
416458

417459
std::error_code is_local(const Twine &Path, bool &Result) {
418460
struct STATVFS Vfs;
419-
if (::STATVFS(Path.str().c_str(), &Vfs))
461+
if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
420462
return std::error_code(errno, std::generic_category());
421463

422464
Result = is_local_impl(Vfs);

llvm/unittests/Support/Path.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,6 +1492,29 @@ TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) {
14921492
verifyWrite(FD, "Buzz", true);
14931493
}
14941494

1495+
TEST_F(FileSystemTest, is_local) {
1496+
bool TestDirectoryIsLocal;
1497+
ASSERT_NO_ERROR(fs::is_local(TestDirectory, TestDirectoryIsLocal));
1498+
EXPECT_EQ(TestDirectoryIsLocal, fs::is_local(TestDirectory));
1499+
1500+
int FD;
1501+
SmallString<128> TempPath;
1502+
ASSERT_NO_ERROR(
1503+
fs::createUniqueFile(Twine(TestDirectory) + "/temp", FD, TempPath));
1504+
FileRemover Cleanup(TempPath);
1505+
1506+
// Make sure it exists.
1507+
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
1508+
1509+
bool TempFileIsLocal;
1510+
ASSERT_NO_ERROR(fs::is_local(FD, TempFileIsLocal));
1511+
EXPECT_EQ(TempFileIsLocal, fs::is_local(FD));
1512+
1513+
// Expect that the file and its parent directory are equally local or equally
1514+
// remote.
1515+
EXPECT_EQ(TestDirectoryIsLocal, TempFileIsLocal);
1516+
}
1517+
14951518
TEST_F(FileSystemTest, set_current_path) {
14961519
SmallString<128> path;
14971520

0 commit comments

Comments
 (0)