Selection of a file by permissions in linux - c++

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);
}
}

Related

Printing All The Files Path's In C:\ With 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;
}
}
}

readFile function not working on second iteration with different argument - c++

I've written a readFile function for a project I'm working on. I call it once, load in a file and read in it's contents - works fine
However, when I try to load it a second time, attempting to change the file name - it loads it in, saves it to a static string 'path' that I access in a different function - but then the function is not printing the data
The question is, how do I change the file name, and read it in successfully on the second iteration? The part that has me stumped is that it works once, but not twice
Ive attempted to use cin.ignore(); cin.clear(); cin.sync() on the second iteration of fileName function - but none of them allow a separate file to be read successfully.
Minimum Reproducible Example:
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <vector>
#include <sstream>
#include <iomanip>
#include <iostream>
using namespace std;
static string path;
string opt;
void readFile();
int fileName();
void menu() { // put in while loop - while True
cout << "----------------------" << endl;
cout << "R(ead) -" << "Read File" << endl;
cout << "F(ile) -" << "Set Filename" << endl;
cout << "\nPlease select from the above options" << endl;
cin >> opt;
cout << "\nInput entered: " << opt << endl;
if (opt == "R") {
readFile();
}
if (opt == "F") {
fileName();
}
}
void readFile() { // doing this twice
ifstream readFile;
readFile.open(path);
if (!readFile.is_open()) {
cout << "Could not read file" << endl;
}
string str;
int i = 0;
while (getline(readFile, str))
{
if (str[0] != '/')
{
cout << "DEBUG: Line is - " << str << endl;
}
}
readFile.clear();
readFile.close();
menu();
}
int fileName() {
cout << "File path: ";
if (path != "") {
cin.ignore();
cin.clear();
cin.sync();
}
getline(cin, path);
ifstream file(path.c_str());
if (!file) {
cout << "Error while opening the file" << endl;
return 1;
}
cout << "(File loaded)" << endl;
cout << "Path contains: " << path << endl;
file.clear();
file.close();
menu();
}
int main()
{
fileName();
}
Sample text, saved as txt file and read in using path:
Data1.txt
// standard test file
123,Frodo inc,2006, lyons,"1,021,000.16",0.0,
U2123,Sam Inc,2006, lyons,"21,600.00",13.10,123
A721,Merry Inc,2604, Kingston,"21,600.10",103.00,
U2122,Pippin Inc,2612, reid,"21,600.00",0
U1123,Huckelberry corp,2612, Turner,"21,600.00",13.10,
Data2.txt
7101003,Mike,23 boinig road,2615,48000,12000,0
7201003,Jane Philips,29 boinig cresent,2616,47000,12000,0
7301003,Philip Jane,23 bong road,2615,49000,000,0
7401004,Peta,23 bong bong road,2615,148000,19000,0
7101205,Abdulla,23 Station st,2615,80000,21000,0
The problem comes from reading in one, and trying to read in the other after the first has been executed.
Enter Filename
Hit Readfile
Return to menu, hit Set Filename
Change to Data2.txt
Readfile again. Not working
My tutor told me "That's not how functions work in c++" but didn't elaborate further, and is unavailable for contact.
In general, do not use global variables. The path variable should be passed as a parameter, not kept as a global variable altered between function calls, as this leads to many side effects and is the source of countless bugs. See the following refactoring:
void menu() { // put in while loop - while True
while(true)
{
//Keep this as a local variable!
std::string opt;
std::string filename;
cout << "----------------------\n";
cout << "R(ead) -" << "Read File\n";
cout << "F(ile) -" << "Set Filename\n";
cout << "\nPlease select from the above options\n";
cin >> opt;
cout << "\nInput entered: " << opt << '\n';
if (opt == "R") {
readFile(filename);
}
if (opt == "F") {
filename = getFileName();
}
}
}
void readFile(const std::string & filename) {
ifstream readFile;
readFile.open(filename);
if (!readFile.is_open()) {
cout << "Could not read file " << filename << '\n';
}
string str;
int i = 0;
while (getline(readFile, str))
{
if (str[0] != '/')
{
cout << "DEBUG: Line is - " << str << '\n';
}
}
readFile.close();
//just return to get back to menu
return;
}
std::string getFileName() {
cout << "File path: ";
std::string path;
getline(cin, path);
ifstream file(path.c_str());
if (!file) {
cout << "Error while opening the file" << '\n';
//Instead of returning an error code use an exception preferably
}
cout << "(File loaded)" << '\n';
cout << "Path contains: " << path << '\n';
file.close();
return path;
}
Other notes:
Ideally, do input in output in just one function, not all three as it gets confusing exactly what each function is responsible for.
If you want something to hold a file and print the contents, you can use an class.
The file is checked if it is openable twice, not really any reason to do this just delegate that responsibility to one function.
One of the best things about C++ is RAII and deterministic lifecycles for objects and primitives - use it!! Do not give everything a long life with global variables - use smart parameters and return values instead.

How to get output from other command line interface programs?

Ok I did some research and I couldn't turn up anything useful. I am trying to write a program that will receive input from iwconfig (on a linux machine). It will then sort through the input, do some calculations and output to a database. Sorting through the input and outputting isn't an issue (or so I really hope it not to be) but what I am struggling with is reading input from another command line program. What I have right now as a base Hello World program is:
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
int numbr = 0;
cout << "Hello world!" << endl;
cin >> numbr;
cout << "number is " << numbr;
cout << system("iwconfig");
return 0;
}
However upon running the program, all it does is output hello world, ask for my random input and output it again. It does not output iwconfig (I also ran the line as just system("iwconfig"); without the output statement). Would someone be kind enough to explain how I could run a program like iwconfig and capture it's output?
"Would someone be kind enough to explain how I could run a program like iwconfig and capture it's output?"
Check the int system( const char *command ); documentation. It certainly doesn't provide to return the value, you want to output with your cout statement.
You probably want to have pipes established between your main and the iwconfig program, as described here, to control the input and output streams used by the child process.
To replicate the mentioned answer adapted:
int main() {
int fd_p2c[2], fd_c2p[2], bytes_read;
pid_t childpid;
char readbuffer[80];
string program_name = "iwconfig";
string receive_output = "";
if (pipe(fd_p2c) != 0 || pipe(fd_c2p) != 0) {
cerr << "Failed to pipe\n";
exit(1);
}
childpid = fork();
if (childpid < 0) {
cout << "Fork failed" << endl;
exit(-1);
}
else if (childpid == 0) {
if (dup2(fd_p2c[0], 0) != 0 ||
close(fd_p2c[0]) != 0 ||
close(fd_p2c[1]) != 0) {
cerr << "Child: failed to set up standard input\n";
exit(1);
}
if (dup2(fd_c2p[1], 1) != 1 ||
close(fd_c2p[1]) != 0 ||
close(fd_c2p[0]) != 0) {
cerr << "Child: failed to set up standard output\n";
exit(1);
}
execl(program_name.c_str(), program_name.c_str(), (char *) 0);
cerr << "Failed to execute " << program_name << endl;
exit(1);
}
else {
close(fd_p2c[0]);
close(fd_c2p[1]);
cout << "Writing to child: <<" << gulp_command << ">>" << endl;
int nbytes = gulp_command.length();
if (write(fd_p2c[1], gulp_command.c_str(), nbytes) != nbytes) {
cerr << "Parent: short write to child\n";
exit(1);
}
close(fd_p2c[1]);
while (1) {
bytes_read = read(fd_c2p[0], readbuffer, sizeof(readbuffer)-1);
if (bytes_read <= 0) break;
readbuffer[bytes_read] = '\0';
receive_output += readbuffer;
}
close(fd_c2p[0]);
cout << "From child: <<" << receive_output << ">>" << endl;
}
return 0;
}

readdir doesn't work properly in linux system

EDITED with full code :
int filename_extract(){
DIR *pDIR;
struct dirent *entry;
string file;
try{
if((pDIR=opendir("/home/xxx/Documents/enron_mail_20110402/maildir/allen-p/all_documents")) != NULL){
while((entry = readdir(pDIR))!=NULL){
if( strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 ){
file = entry->d_name;
cout << file << " "; // Doesn't print anything
}
}
closedir(pDIR);
}
}catch(exception &e){
cout << "Error occured in filename_extract function " << e.what() << endl;
}
return 0;
}
But entry->d_name isn't storing any of the file names from the directory and /home/xxx/Documents/enron_mail_20110402/maildir/allen-p/all_documents folder contain files of plain text document type namely:
1.
2.
3.
4.
....
648.
Why is it not working properly and where I'm doing it wrong?

After dragging a file on exe, ifstream fails to open file

I have have the following problem:
When I drag and drop a file to my tool (exe) when ifstream fails to open the file.
If I give it manually though the console it works!
I don't get where the diffenence is, because I am cutting the path and passing just the filename.
Have a look at the code:
int main(int argc, char* argv[]) {
if (argc < 2) {
cout
<< "ERROR: Wrong amount of arguments! Give at least one argument ...\n"
<< endl;
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
exit(1);
return 0;
}
vector<string> files;
for (int g = 1; g < argc; g++) {
string s = argv[g];
cout<<"parameter at: " << g << " = " << argv[g] << "\n" << endl;
string filename = "";
int pos = s.find_last_of("\\", s.size());
if (pos != -1) {
filename.append(s.substr(pos + 1));
// cout<<" cutted path: " << s.substr(0,s.size()-filename.size()) << endl;
// cout << "argv[1] " << argv[1] << endl;
cout << "\n filename: " << filename << "\t pos: " << pos << endl;
files.push_back(filename);
}
files.push_back(s);
}
for (unsigned int k = 0; k < files.size(); k++)
{
cout << "files.at( " << k << " ): " << files.at(k).c_str() << endl;
Converter a(files.at(k).c_str());
a.getCommandsFromCSV();
a.saveConvertedFile();
}
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
return 0;
}
It fails already on the constructor:
Converter::Converter(const char* file) {
filename = file;
myfile.open(filename.c_str(), ios_base::in);
cout << (myfile ? "open successful on constructor " : "some error on constructor");
cin.ignore();
trace_raw = "";
}
You have any idea why?
UPDATE:
The file as parameter works now. The solution was to leave the full path.
Anyway I have the same error on a hard coded file. I thought it may be the same that's why I added .\ at the beginning of the file name... without success.
The code:
void GenericCommandConverter::getATCommandsFromCSV() {
cout << "\t| +++++++++++getATCommandsFromCSV() started+++++++++++++ |"
<< endl;
/*
* CSV file name is hardcoded
*/
string filename_csv = ".\\test.csv";
string commands = "";
int pos_start = 0;
int pos_end = 0; // "|"
int substrLength = 0;
int separator_count = 0;
char c;
vector<string> lines;
vector<string> commandList;
vector<vector<string> > linesSeparated;
ifstream csvFile;
csvFile.open(filename_csv.c_str(), ios_base::in);
cout << (myfile ? "open successful on getATCommandsFromCSV " : "some error on getATCommandsFromCSV ");
cin.ignore();
...
UPDATE2:
The solution was: on dropping a file to the exe, the "root" folder changes to the one where the dropped file comes from. Giving the hardcoded file the path from the *.exe solved it!
I am guessing your current directory is wrong. Don't cut the path off. Anyway you should do error checking / debugging to see why it couldn't open the file. Diligent debugging is essential for solving problems without having to make blind guesses.