readdir doesn't work properly in linux system - c++

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?

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

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

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

How to convert a text file from Windows to Unix

When converting from Unix to Windows, I get the correct output; however, when going from Windows to Unix I get some strange output. I thought all I had to allow for was the removal of the carriage return, '\r'. This isn't working though. When I open the text file after running the code, I get some strange results, the first line is correct, and then all hell breaks lose.
int main( )
{
bool windows = false;
char source[256];
char destination[256]; // Allocate the max amount of space for the filenames.
cout << "Please enter the name of the source file: ";
cin >> source;
ifstream fin( source, ios::binary );
if ( !fin ) // Check to make sure the source file exists.
{
cerr << "File " << source << " not found!";
getch();
return 1;
}//endif
cout << "Please enter the name of the destination file: ";
cin >> destination;
ifstream fest( destination );
if ( fest ) // Check to see if the destination file already exists.
{
cout << "The file " << destination << " already exists!" << endl;
cout << "If you would like to truncate the data, please enter 'Y', "
<< "otherwise enter 'N' to quit: ";
char answer = char( getch() );
if ( answer == 'n' || answer == 'N' )
{
return 1;
}//endif
}//endif
clrscr(); // Clear screen for neatness.
ofstream fout( destination, ios::binary );
if ( !fout.good() ) // Check to see if the destination file can be edited.
{
cout << destination << "could not be opened!" << endl;
getch();
return 1;
}//endif
// Open the destination file in binary mode.
fout.open( destination, ios::binary );
char ch = fin.get(); // Set ch to the first char in the source file.
while ( !fin.eof() )
{
if ( ch == '\x0D' ) // If ch is a carriage return, then the source file
{ // must be in a windows format.
windows = true;
}//endif
if ( windows == true )
{
ch = fin.get(); // Advance ch, so that at the bottom of the loop, the
}//endif // carriage return is not coppied into the new file.
if ( windows == false )
{
if ( ch == '\x0A' ) // If the file is in the Unix format..
{
fout.put( '\x0D' ); // When a new line is found, output a carriage
}//endif // return.
}//endif
fout.put( ch );
ch = fin.get();
}//endwh
if ( windows == true )
{
fout.put( '\x0A' );
}//endif
fout.close();
fin.close(); // Close yer files.
if ( windows == true ) // A little output for user-friendly-ness.
{
cout << "The contents of " << source << " have been coppied to "
<< destination << " and converted to Unix format." << endl;
}else{
cout << "The contents of " << source << " have been coppied to "
<< destination << " and converted to Windows format." << endl;
}//endif
cout << "Enter any key to quit.." << endl;
getch();
return 0;
}//endmn
*If* you only need to convert simple ascii (and perhaps utf-8) text files, you could read the source file line-by-line in a loop in translated mode (handles newlines for you enough for this case) with non-member getline() and then output the lines to the output file while inserting \n or \r\n after each line except the last.
Then, you can remove the original file and rename the temp file to have the original file's name. Or, if you want, you can instead push_back the lines into a vector<string>. Then, you could close the input handle to the file, do ofstream out("filename", ios_base::trunc) and write the elements of the vector to the file while separating them by the newlines you want.
It all depends on your requirements.
The following is an example with minimal error handling. But, it's really only the FOR loop and reading line-by-line that I want to show here as a different way of doing things.
convert_file.exe "test.txt" "linux"
convert_file.exe "test.txt" "win"
#include <iostream>
#include <string>
#include <fstream>
#include <ostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
int main(int argc, char* argv[]) {
if (argc != 3) {
cerr << "Usage: this.exe file_to_convert newline_format(\"linux\" or \"win\")" << endl;
return EXIT_FAILURE;
}
string fmt(argv[2]);
if (fmt != "linux" && fmt != "win") {
cerr << "Invalid newline format specified" << endl;
return EXIT_FAILURE;
}
ifstream in(argv[1]);
if (!in) {
cerr << "Error reading test.txt" << endl;
return EXIT_FAILURE;
}
string tmp(argv[1]);
tmp += "converted";
ofstream out(tmp.c_str(), ios_base::binary);
if (!out) {
cerr << "Error writing " << tmp << endl;
return EXIT_FAILURE;
}
bool first = true;
for (string line; getline(in, line); ) {
if (!first) {
if (fmt == "linux") {
out << "\n";
} else {
out << "\r\n";
}
}
out << line;
first = false;
}
in.close();
out.close();
if (remove(argv[1]) != 0) {
cerr << "Error deleting " << argv[1] << endl;
return EXIT_FAILURE;
}
if (rename(tmp.c_str(), argv[1]) != 0) {
cerr << "Error renaming " << tmp << " to " << argv[1] << endl;
return EXIT_FAILURE;
}
}
As others have said though, there are already utilities (including text editors like Notepadd++) that do newline conversion for you. So, you don't need to implement anything yourself unless you're doing this for other reasons (you didn't specify).
Don't worry about checking for windows in the loop. Simply check for a carriage return. Set a variable 'carriage_return.' Next iteration, if 'carriage-return' and ch != linefeed, simply insert a linefeed. Then reset the carriage_return variable to false. It's a very simple and basic rule which won't send you wrong.
bool carriage_return = false;
const char linefeed = '\n'; // Is it? I forget.
const char cr = '\r'; // I forget again. Too late to check.
char ch = fin.get();
if (ch == cr) carriage_return = true;
while (!fin.eof()){
if (carriage_return) { // Check if we already have a newline
if (ch != linefeed) { // If we have a newline previously, we need a linefeed. If it's already there just leave it, if it isn't there put it in
fout.put(linefeed);
}
if (ch != cr) carriage_return = false; // Reset the carriage-return flag *if* we don't have another carriage return. This handles multiple empty lines in an easy way for us.
}
fout.put(ch);
ch = fin.get();
}
I have re-edit your code and it works fine for me..
Hope this helps !
#include <iostream>
#include <fstream>
#include <iostream>
#include<stdio.h>
using namespace std;
int main( )
{
bool windows = false;
char source[256];
char destination[256]; // Allocate the max amount of space for the filenames.
cout << "Please enter the name of the source file: ";
cin >> source;
ifstream fin( source, ios::binary );
if ( !fin ) // Check to make sure the source file exists.
{
cerr << "File " << source << " not found!";
return 1;
}//endif
cout << "Please enter the name of the destination file: ";
cin >> destination;
ifstream fest( destination );
if ( fest ) // Check to see if the destination file already exists.
{
cout << "The file " << destination << " already exists!" << endl;
cout << "If you would like to truncate the data, please enter 'Y', "
<< "otherwise enter 'N' to quit: ";
char answer;
cin >> answer;
if ( answer == 'n' || answer == 'N' )
{
return 1;
}
}
//clrscr();
ofstream fout( destination);
if ( !fout.good() )
{
cout << destination << "could not be opened!" << endl;
return 1;
}
char ch = fin.get();
while (!fin.eof())
{
if ( ch == '\r' )
{
windows = true;
}
if ( ch == '\n' && windows == false ) // If the file is in the Unix format..
{
// Don't do anything here
}
fout.put( ch );
cout << ch; // For Debugging purpose
ch = fin.get();
}
fout.close();
fin.close();
if ( windows == true ) // A little output for user-friendly-ness.
{
cout<<endl;
cout << "The contents of " << source << " have been coppied to "
<< destination << " and converted to Unix format." << endl;
}else{
cout << "The contents of " << source << " have been coppied to "
<< destination << " and converted to Windows format." << endl;
}//endif
cout << "Enter any key to quit.." << endl;
return 0;
}
Did you make sure you're reading in the data in the right format and saving it in the right format?
Trying to work with a different character encoding and just 'reading' it in leads to very bad things :|
And you then also have to account for different replacements that need to be done.
This may help link

Why is this string changed?

I have the following code, so far, I want to check if a file name is already in the linked list fileList (or flist). according to the output, the string saved in the first Node was changed somewhere in Node* getFileName(Node *&flist) How did this happen? Also, is there anything else that I'm doing is wrong or not safe regarding pointers of Node and strings?
output:
in main: file4.txt
start of process: file4.txt
file4.txt
mid of process: file4.txt"
in contains, fileName in node: file4.txt"
in contains, target file name: file4.txt
end of process: file4.txt"
0
no recursive call
code:
struct Node {
string fileName;
Node *link;
};
/*
*
*/
bool contains (Node *&flist, string &name) {
Node *tempNode = *&flist;
while (tempNode != 0) {
cout << "in contains, fileName in node: " << flist->fileName << endl;
cout << "in contains, target file name: " << name << endl;
if ((tempNode->fileName) == name) {
return true;
}
else {
tempNode = tempNode->link;
}
}
return false;
}
/*
*
*/
Node* getLastNode (Node *&flist) {
Node *tempNode = *&flist;
while (tempNode != 0) {
tempNode = tempNode->link;
}
return tempNode;
}
/*
*
*/
string getFileName(string oneLine) {
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
cout << sub << endl;
return sub;
}
return NULL;
}
/*
*
*/
void process( istream &in, ostream &out, Node *&flist ) {
cout << "start of process: " << flist->fileName << endl;
string oneLine; //temp line holder
while (getline(in, oneLine)) {
// cout << oneLine << endl;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos) {
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
cout << "mid of process: " << flist->fileName << endl;
bool recursive;
recursive = contains(flist, name);
cout << "end of process: " << flist->fileName << endl;
cout << recursive << endl;
if (recursive) {
//contains recursive include
cerr << "recursive include of file " << name << endl;
exit(-1);
}
else {
//valid include
cout << "no recursive call" << endl;
}//else
}//if
}//while
}//process
/*
*
*/
int main( int argc, char *argv[] ) {
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
switch ( argc ) {
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
processOneFile (*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Could you post the original code? The code you posted doesn't even compile.
Errors I've noticed, in order:
processOneFile (*infile, *outfile, fileList);
There is no processOneFile() procedure.
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
case 1: // use cin and cout
break;
processOneFile (*infile, *outfile, fileList);
This will call processOneFile() with an uninitialized file list, which will crash when you try to print the file name.
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
aFile is only in scope within that else, so trying to use a pointer to it later will fail.
string getFileName(string oneLine) {
///
return NULL;
}
You can't construct a std::string from NULL -- this will crash the program.
After fixing these errors so your code wouldn't crash, I couldn't reproduce the error.
If you're building in Linux, try increasing the warning level (with g++ -Wall -Wextra -ansi -pedantic) and running your code through valgrind, to check for memory errors.
Ok, the code does now seem like it works as expected:
#include <iostream>
#include <fstream>
using namespace::std;
struct Node
{
string fileName;
Node *link;
};
bool contains (Node *&flist, string &name)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
cout << "Searching in \"" << flist->fileName;
cout << "\" for \"" << name << "\"" << endl;
if ( tempNode->fileName == name)
{
return true;
}
else
{
tempNode = tempNode->link;
}
}
return false;
}
Node* getLastNode (Node *&flist)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
tempNode = tempNode->link;
}
return tempNode;
}
string getFileName(string oneLine)
{
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
return sub;
}
return "";
}
void process( istream &in, ostream &out, Node *&flist )
{
cout << "Start of process: " << flist->fileName << endl << endl;
string oneLine;
while (1)
{
cout << "Input include statement: ";
getline(in, oneLine);
if (oneLine == "STOP")
return;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos)
{
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
if (name == "")
{
cout << "Couldn't find filename, skipping line..." << endl;
continue;
}
if (contains(flist, name))
{
//contains recursive include
cerr << "Uh, oh! Recursive include of file " << name << endl;
exit(-1);
}
else
{
cerr << "No recursive include" << endl;
}
}//if
cout << endl;
}//while
}
int main( int argc, char *argv[] )
{
Node* fileList = new Node;
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
fileList->fileName = "Input"; // default value
switch ( argc )
{
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
fileList->fileName = argv[1];
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
process(*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Also, why are you wasting time writing your own linked list when the standard library already has a perfectly good one?