I have some code to list the files in a directory. For Windows Systems, I'm hoping to end up with a list of files and folders that matches what you'd see in Windows Explorer. For example, when I list C:\ on Server 2016, I want to have the Users
folder but not the Documents and Settings
junction. Currently I'm getting both, with no apparent way of differentiating between them.
My current code looks like this:
boost::filesystem::directory_iterator itr(dir);
boost::filesystem::directory_iterator end;
Poco::SharedPtr<Poco::JSON::Array> fileList(new Poco::JSON::Array);
for (; itr != end; ++itr) {
boost::filesystem::path entryPath = itr->path();
Poco::File file(entryPath.string());
// ...
I tried the Poco isLink()
method, but it returns false for junctions.
I also tried Poco::DirectoryIterator
, which gives the same behavior as Boost, and Poco::SortedDirectoryIterator
, which always throws File access error: sharing violation: \pagefile.sys
when reading C:\
.
Ideally, this code should include symlinks on Linux and MacOS systems, while ignoring junctions on Windows.
Here's what I eventually came up with. It isn't a perfect solution - it's more of a heuristic than a proper identifier - but it seems to work well enough for my use case:
#ifdef _WIN32
#include <windows.h>
#endif
bool FileController::isNtfsJunction(const std::string& dirPath) const {
#ifdef _WIN32
DWORD attrs = GetFileAttributesA(dirPath.c_str());
if (INVALID_FILE_ATTRIBUTES == attrs) {
DWORD err = GetLastError();
logger.error("Could not determine if path is NTFS Junction: %s. Error: %s", dirPath, err);
return false;
}
return attrs & FILE_ATTRIBUTE_DIRECTORY &&
attrs & FILE_ATTRIBUTE_REPARSE_POINT &&
attrs & FILE_ATTRIBUTE_HIDDEN &&
attrs & FILE_ATTRIBUTE_SYSTEM;
#else
return false;
#endif
}