in watchman/fs/FileDescriptor.cpp [250:358]
w_string FileDescriptor::getOpenedPath() const {
#if defined(F_GETPATH)
// macOS. The kernel interface only allows MAXPATHLEN
char buf[MAXPATHLEN + 1];
if (fcntl(fd_, F_GETPATH, buf) == -1) {
throw std::system_error(
errno, std::generic_category(), "fcntl for getOpenedPath");
}
return w_string(buf);
#elif defined(__linux__) || defined(__sun)
char procpath[1024];
#if defined(__linux__)
snprintf(
procpath,
sizeof(procpath),
"/proc/%d/fd/%d",
folly::get_cached_pid(),
fd_);
#elif defined(__sun)
snprintf(
procpath,
sizeof(procpath),
"/proc/%d/path/%d",
folly::get_cached_pid(),
fd_);
#endif
// Avoid an extra stat by speculatively attempting to read into
// a reasonably sized buffer.
char buf[WATCHMAN_NAME_MAX];
auto len = readlink(procpath, buf, sizeof(buf));
if (len == sizeof(buf)) {
len = -1;
// We need to stat it to discover the required length
errno = ENAMETOOLONG;
}
if (len >= 0) {
return w_string(buf, len);
}
if (errno == ENOENT) {
// For this path to not exist must mean that /proc is not mounted.
// Report this with an actionable message
throw std::system_error(
ENOSYS,
std::generic_category(),
"getOpenedPath: need /proc to be mounted!");
}
if (errno != ENAMETOOLONG) {
throw std::system_error(
errno, std::generic_category(), "readlink for getOpenedPath");
}
// Figure out how much space we need
struct stat st;
if (fstat(fd_, &st)) {
throw std::system_error(
errno, std::generic_category(), "fstat for getOpenedPath");
}
std::string result;
result.resize(st.st_size + 1, 0);
len = readlink(procpath, &result[0], result.size());
if (len == int(result.size())) {
// It's longer than we expected; TOCTOU detected!
throw std::system_error(
ENAMETOOLONG,
std::generic_category(),
"readlinkat: link contents grew while examining file");
}
if (len >= 0) {
return w_string(&result[0], len);
}
throw std::system_error(
errno, std::generic_category(), "readlink for getOpenedPath");
#elif defined(_WIN32)
std::wstring wchar;
wchar.resize(WATCHMAN_NAME_MAX);
auto len = GetFinalPathNameByHandleW(
(HANDLE)fd_,
&wchar[0],
wchar.size(),
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
auto err = GetLastError();
if (len >= wchar.size()) {
// Grow it
wchar.resize(len);
len = GetFinalPathNameByHandleW(
(HANDLE)fd_, &wchar[0], len, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
err = GetLastError();
}
if (len == 0) {
throw std::system_error(
GetLastError(), std::system_category(), "GetFinalPathNameByHandleW");
}
return w_string(wchar.data(), len);
#else
throw std::system_error(
ENOSYS,
std::generic_category(),
"getOpenedPath not implemented on this platform");
#endif
}