Printing All The Files Path's In C:\ With C++ - c++

I tried to print all the files path's in C:.
But I saw that I am getting permission errors.
void getAllFilesInDirectory(wstring directoryPath, vector<wstring> &files) {
for (filesystem::directory_entry directory : filesystem::directory_iterator(directoryPath)) {
if (GetFileAttributesW(directory.path().wstring().c_str()) == FILE_ATTRIBUTE_SYSTEM)
continue;
//Checking if directory.path is a file or a directory
if (GetFileAttributesW(directory.path().wstring().c_str()) == FILE_ATTRIBUTE_NORMAL) {
files.push_back(directory.path().wstring());
wcout << "The path is " << directory.path().wstring() << endl;
continue;
}
try {
for (filesystem::directory_entry file : filesystem::recursive_directory_iterator(directory)) {
if (GetFileAttributesW(file.path().wstring().c_str()) == FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
wcout << "The path of the file is " << file.path().wstring() << endl;
files.push_back(file.path().wstring());
}
} catch (exception &e) {
wcout << "There is exception " << e.what() << " and the directory path is: " << directory.path().wstring()
<< endl;
}
}
}
My code is working when I give the function a regular directory (not one with privileges).
But when I give him "C:\" he quitting after printing a little path's.
It will be great if someone post his method for printing all the path's in the C drive.
Thanks!

You said in comments that:
I want that my code will ignore files that he doesn't have access to them
std::filesystem::directory_iterator and std::filesystem::recursive_directory_iterator both have a constructor that accepts a std::filesystem::directory_options enum as input, which has a skip_permission_denied item available for that purpose, for example:
void getAllFilesInDirectory(const wstring &directoryPath, vector<wstring> &files) {
for (filesystem::directory_entry directory : filesystem::directory_iterator(directoryPath, filesystem::directory_options::skip_permission_denied)) {
...
for (filesystem::directory_entry file : filesystem::recursive_directory_iterator(directory, filesystem::directory_options::skip_permission_denied)) {
...
}
}
}
On a side note, you may want to consider adding a namespace alias to shorten those qualified names, eg:
namespace fs = std::filesystem;
for (fs::directory_entry directory : fs::directory_iterator(directoryPath, fs::directory_options::skip_permission_denied)) {
...
for (fs::directory_entry file : fs::recursive_directory_iterator(directory, fs::directory_options::skip_permission_denied)) {
...
}
}
Also, your use of GetFileAttributesW() is wrong. You are not checking for errors, and you are not taking into account that folders and files can (and usually do) have multiple attributes assigned. Use the & (AND) operator when testing for specific attributes. And testing for the FILE_ATTRIBUTE_NORMAL attribute is not the correct way to differentiate a file from a folder. Test for the presence/lack of the FILE_ATTRIBUTE_DIRECTORY attribute instead.
Try this:
namespace fs = std::filesystem;
void getAllFilesInDirectory(const wstring &directoryPath, vector<wstring> &files) {
for (fs::directory_entry directory : fs::directory_iterator(directoryPath, fs::directory_options::skip_permission_denied)) {
DWORD attrs = GetFileAttributesW(directory.path().wstring().c_str());
if (attrs == INVALID_FILE_ATTRIBUTES) {
DWORD err = GetLastError();
wcerr << "Error " << err << " getting attributes for path " << directory.path().wstring() << endl;
continue;
}
if (attrs & FILE_ATTRIBUTE_SYSTEM)
continue;
//Checking if directory.path is a file or a directory
if (attrs & ~FILE_ATTRIBUTE_DIRECTORY) {
files.push_back(directory.path().wstring());
wcout << "The path is " << directory.path().wstring() << endl;
continue;
}
try {
for (fs::directory_entry file : fs::recursive_directory_iterator(directory, fs::directory_options::skip_permission_denied)) {
attrs = GetFileAttributesW(file.path().wstring().c_str());
if (attrs == INVALID_FILE_ATTRIBUTES) {
DWORD err = GetLastError();
wcerr << "Error " << err << " getting attributes for path " << file.path().wstring() << endl;
continue;
}
if (attrs & FILE_ATTRIBUTE_DIRECTORY)
continue;
wcout << "The path of the file is " << file.path().wstring() << endl;
files.push_back(file.path().wstring());
}
} catch (const exception &e) {
wcout << "There is exception " << e.what() << " and the directory path is: " << directory.path().wstring() << endl;
}
}
}

Related

C++ how to make a root of .cfg file

I have this .cfg file and my problem is that I am trying to read and extract info using the libconfig library in the .cfg file but I can't create a root up to the AboCombi element. I would like to know how to create a root of more than 2 elements of a hierarchy.
myConfig.cfg
clients =
{
name = "Robert";
client_infos = (
{
town = "Koeln";
Start_abo = "09.12.2020";
AboCombi = (
{
Courses = "All";
Materials = "ADTF_For_Free";
Matric = "A0003";
},
);
},
};
int main(int argc, char** argv) {
(void)argc;
(void)argv;
Config cfg;
// Read the file. If there is an error, report it and exit.
try
{
cfg.readFile("myConfig.cfg");
}
catch (const FileIOException &fioex)
{
cerr << "I/O error while reading file." << endl;
return(EXIT_FAILURE);
}
catch (const ParseException& pex)
{
cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
<< " - " << pex.getError() << endl;
return(EXIT_FAILURE);
}
const Setting& root = cfg.getRoot();
// Output a list of the main config file.
try
{
const Setting &croot = root["clients"]["client_infos"]; // but I would like to go further down the hierarchy to AboCombi and its elements
int count = croot.getLength();
cout << count << endl;
}
catch (const SettingNotFoundException &nfex)
{
// Ignore.
}
return(EXIT_SUCCESS);
}

c++ filesystem out of root

I`l trying to catch wrong paths in input args in my code and found that behavior.
code example:
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;
int main() {
fs::path p = "/home";
cout << p << endl; // "/home"
cout << fs::exists(p) << endl; // 1
try {
p = p / "../..";
cout << p << endl; // "/home/../.."
cout << fs::exists(p) << endl; // 1
} catch (...) {
cout << "catched" << endl;
}
p = fs::canonical(p);
cout << p << endl; // "/"
cout << fs::exists(p) << endl; // 1
return 0;
}
How to catch out of bounds of the root with the standard capabilities? Is this a bug or a feature?
Like everyone else said, you cannot "go out of bounds" with relative parent directory (..).
That said, you can check the depth of a given path:
The path can be traversed element-wise via iterators returned by the begin() and end() functions, which views the path in generic format and iterates over root name, root directory, and the subsequent file name elements (directory separators are skipped except the one that identifies the root directory). If the very last element in the path is a directory separator, the last iterator will dereference to an empty element.
Live On Coliru
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
std::cout << std::boolalpha;
for (fs::path p :
{
"/home",
"/home/sehe",
"/home/",
"//home/",
"/home/sehe/",
}) //
{
try {
p = canonical(absolute(p));
std::cout << " -- " << p << " (" << exists(p) << ")\n";
std::cout << "elements:";
for (auto& el : p) {
std::cout << " " << el << ";";
}
std::cout << "\n";
if (std::distance(p.begin(), p.end()) < 3) {
std::cout << "Does not have two unique parents\n";
} else {
p = p / "../..";
std::cout << "Up two: " << p << " (" << exists(p) << ")\n";
}
} catch (std::exception const& e) {
std::cout << "error " << e.what() << "\n";
}
}
}
On my machine prints:
-- "/home" (true)
elements: "/"; "home";
Does not have two unique parents
-- "/home/sehe" (true)
elements: "/"; "home"; "sehe";
Up two: "/home/sehe/../.." (true)
-- "/home" (true)
elements: "/"; "home";
Does not have two unique parents
-- "/home" (true)
elements: "/"; "home";
Does not have two unique parents
-- "/home/sehe" (true)
elements: "/"; "home"; "sehe";
Up two: "/home/sehe/../.." (true)

C++ QueryDosDeviceA() return 0 but COMX is connected

so I'm doing a function to retrieve all the COM serial port names connected to the system using QueryDosDeviceA
I tried to use CreatFileA with "\\\\.\\COM6", and it doesn't throw me any errors.
But QueryDosDeviceA with "COM6" or "\\\\.\\COM6"
Function.cpp
std::vector<std::string> SerialPort::_SerialList()
{
std::vector<std::string> serialList;
std::string COMName("\\\\.\\COM"), queryName(COMName); //also tried with COMName("COM")
CHAR bufferTragetPath[5000];
std::string tmp;
DWORD path_size(0);
//test each COM name to get the one used by the system
for (int i(0); i < 255; i++)
{
queryName = COMName + std::to_string(i);
//Query the path of the COMName
path_size = QueryDosDeviceA((LPCSTR)&queryName, (LPSTR)&bufferTragetPath, 5000);
std::cout << std::endl << "Path for " << queryName << ":" << path_size;
if (path_size != 0) {
std::cout << "pushing..." << queryName << " on " << bufferTragetPath << std::endl;
serialList.push_back(queryName);
}
}
return serialList;
}
And here is the output :
Path for \\.\COM0:0
Path for \\.\COM1:0
Path for \\.\COM2:0
Path for \\.\COM3:0
Path for \\.\COM4:0
Path for \\.\COM5:0
Path for \\.\COM6:0
Path for \\.\COM7:0
Path for \\.\COM8:0
Path for \\.\COM9:0
...
Path for \\.\COM253:0
Path for \\.\COM254:0Port name: \\.\COM6
Hello World !
So it's finding nothing but the COM6 port can be used by CreateFileA
Thanks to #user253751, #JohnnyMopp, #dresscherjm
And #RemyLebeau
Here is the code that include the solution:
std::vector<std::string> SerialPort::_SerialList()
{
std::vector<std::string> serialList;
std::string COMName("COM"), queryName("");
CHAR bufferTragetPath[5000];
std::string tmp;
DWORD path_size(0);
//test each COM name to get the one used by the system and get his description name
for (int i(0); i < 255; i++)
{
queryName = COMName + std::to_string(i);
//Query the path of the COMName
path_size = QueryDosDeviceA(queryName.c_str(), bufferTragetPath, 5000);
std::cout << std::endl << "Path for " << queryName << ":" << path_size << " " << queryName;
if (path_size != 0) {
std::cout << "pushing..." << queryName << " on " << bufferTragetPath << std::endl;
serialList.push_back(tmp);
}
}
return serialList;
}
Basically i change the convertion of queryName from string to LPCSTR
//LPCSTR => Long Pointer Const String(= const char)
queryName.c_str() //return queryName as const char*
I've also removed a cast from bufferTragetPath that was useless
//from
(LPSTR)&bufferTragetPath
//to
bufferTragetPath //cause bufferTragetPath is char *

Selection of a file by permissions in linux

Alright, so I'm doing a function in Linux (with C++) in which I gotta retrieve the files inside a directory with a concrete permission, for example: retrieving all the files in X directory with read permission.
To do this I'm using the stat() function and the st_mode variable. The problem is that I seem to be unable to make the stat function return correctly a stat struct (from which I get the needed st_mode).
The function is the following one (not complete yet):
void Search::filePermissionSelection ()
{
dirStream = opendir (directory.c_str());
if (dirStream == NULL)
{
cout << "error reading directory" << endl;
exit (0);
}
else
{
struct stat statResult;
int error = 0;
while ((dirDirent = readdir (dirStream)) != NULL)
{
error = stat (dirDirent->d_name, &statResult);
cout << dirDirent->d_name << " -> Value: " << error << endl;
if (error == 0)
{
if (statResult.st_mode & S_IRUSR) cout << "Read permission ";
if (statResult.st_mode & S_IWUSR) cout << "Write permission ";
if (statResult.st_mode & S_IXUSR) cout << "Exec permission";
cout << endl;
}
}
closedir (dirStream);
}
}

Unit Testing Boost filesystem create_directories

I want to unit test the boost filesystem function create_directories() for it's failure case, i.e., when create_directory fails. Can someone please provide any suggestions on how to do this? Another requirement is that the code needs to be cross-platform.
You could try to create a directory in a path to a file:
#include <fstream>
#include <iostream>
#include "boost/filesystem/path.hpp"
#include "boost/filesystem/operations.hpp"
namespace bfs = boost::filesystem;
int main() {
// Create test dir
boost::system::error_code ec;
bfs::path test_root(bfs::unique_path(
bfs::temp_directory_path(ec) / "%%%%-%%%%-%%%%"));
if (!bfs::create_directory(test_root, ec) || ec) {
std::cout << "Failed creating " << test_root << ": " << ec.message() << '\n';
return -1;
}
// Create file in test dir
bfs::path test_file(test_root / "file");
std::ofstream file_out(test_file.c_str());
file_out.close();
if (!bfs::exists(test_file, ec)) {
std::cout << "Failed creating " << test_file << ": " << ec.message() << '\n';
return -2;
}
// Try to create directory in test_file - should fail
bfs::path invalid_dir(test_file / "dir");
if (bfs::create_directory(invalid_dir, ec)) {
std::cout << "Succeeded creating invalid dir " << invalid_dir << '\n';
return -3;
}
// Try to create nested directory in test_file - should fail
bfs::path nested_invalid_dir(invalid_dir / "nested_dir");
if (bfs::create_directories(nested_invalid_dir, ec)) {
std::cout << "Succeeded creating nested invalid dir " << invalid_dir << '\n';
return -4;
}
// Clean up
bfs::remove_all(test_root);
return 0;
}