"retsize <= sizeInWords" in mbstowcs in dirent.h on Windows - c++

Background information:
I'm building a file tree in windows using dirent.h (project requirement) on VS2013. I got dirent.h from here. I crash at runtime with a debug assertion failed ("retsize <= sizeInWords") from crt\crtw32\mbstowcs.c, line 283.
To test dirent.h, I used
void printDir(std::string dir, std::string tab)
{
DIR* d = opendir(dir.c_str());
dirent* ent = nullptr;
while (ent = readdir(d)) {
if (ent->d_name[0] != '.') {
std::cout << tab << ent->d_name << std::endl;
if (ent->d_type == DT_DIR) {
printDir(dir + "/" + ent->d_name, tab + " ");
}
}
}
}
which worked (called from main as printDir(".", ""))
so to build my tree I have:
struct Dirf {
std::string getFullPath() {
if (out) {
return out->getFullPath() + "/" + ent.d_name;
}
else return ent.d_name;
}
Dirf(DIR* dir, Dirf* parent = nullptr)
: out(parent)
{
if (dir) {
dirent* d = readdir(dir);
if (d) {
ent = *d;
if (dir) {
next = std::make_shared<Dirf>(dir, parent);
}
if (ent.d_type == DT_DIR) {
DIR* inDir = opendir(getFullPath().c_str());
in = std::make_shared<Dirf>(inDir, this);
closedir(inDir);
}
}
}
}
private:
typedef std::shared_ptr<Dirf> point;
friend std::string to_string(Dirf, std::string);
dirent ent;
Dirf* out; // parent to this; in->out == this, out->in == this;
point in, // in != null iff car.d_type == DT_DIR
next; // next entry in the dir
};
std::string to_string(Dirf, std::string tab = "");
However, calling Dirf(opendir(".")) fails with the debug assertion described above

While composing the question, I figured out the answer: I forgot to check for "." and ".." in Dirf's constructor (I remembered to do it in my test case). Adding
while (d && d->d_name[0] == '.') { // skip '..' and '.'
d = readdir(dir);
}
after dirent* d = readdir(dir) made the error go away.

Related

I want to folders parsing only at one level, take folder name and use it to construct path don't want to go in all subdirectory recursively

Following code I have implemented :
I want to search enlist 2 folder present under directory and search for ref .txt file and build path .
Current code is working , But it's searching every subdirectory present in 2 folder inside parent directory. It's delaying the process.
Eg: There are multiple folder/Sub directory present inside A and B both We don't want to traverse inside those .
folder structure is just for reference (but It's on linux)
\A\ref.txt
\B\ref.txt
I want to get A and B only ( 1 level directory parse, make path and read ref.txt)
void getDir(std::string directory)
{
std::string dirToOpen = path + directory;
DIR * dir = opendir(dirToOpen.c_str());
path = dirToOpen + "/";
if(NULL == dir)
return;
struct dirent * entity = readdir(dir);
while(entity != NULL)
{
getEntity(entity);
entity = readdir(dir);
}
path.resize(path.length() - 1 - directory.length());
closedir(dir);
}
void getEntity(struct dirent* entity)
{
if (NULL == entity)
return;
if(entity->d_type == DT_DIR)
{
if(entity->d_name[0] == '.')
{
return;
}
getDir(std::string(entity->d_name));
return;
}
if(entity->d_type == DT_REG)
{
buildPath(std::string(entity->d_name));
return;
}
}
void buildPath(std::string file)
{
if (file == std::string("ref.txt"))
{
std::cout << "file found " << std::endl;
str::string Path_1 = path + file;
}
}

c++ can't seem to filter out the dot files in my recursive directory listing program [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I've written a program to mimic linux's ls and its options:
-a: include dot files
-d: show only this directory
-l: show long form
-h: prints utilities
All the options seem to work fine so far, however, by default when doing something like: ./a.out -d (shows all the files in the current directory) I've set it up so by default the dot files should not be showing(this is setup in function getdir). They should only show when the -a flag is input, something like ./a.out -ad . However, these dot files seem to always be present. Any ideas on what I am doing wrong? (I thought about minimizing the code but decided against it since a lot of the functions are interwined and its easier to see if everything by testing some of the other options).
Sample output:
[John#storm ~]$ ./a.out -d
.ccache
.local
.mozilla
private
public_html
.Xauthority
.bash_history
.bash_logout
.bash_profile
.bashrc
.emacs
.procmailrc
.procmailrc.orig
.config
.esd_auth
OSGradedLabs
linux.txt
OS
omp1.cpp
omp
test.cpp
test2.cpp
test3.cpp
.viminfo
a.out
While it should be:
a.out linux.txt omp omp1.cpp OS OSGradedLabs private public_html test2.cpp test3.cpp test.cpp
#include<iostream>
#include<string.h>
#include<fstream>
#include<dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <string>
#include <vector>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <cstring>
using namespace std;
class dirls
{
public:
dirls();
dirls(bool a, bool d, bool f, bool l, bool h);
void print_usage(string s);
void longlisting(string dir, vector<string>& files);
void getdir(string dir, vector<string>& files, bool recursive);
void initiate(string s, vector<string>& files, vector<string>& paths);
bool ishflag() { return fflag; };
private:
bool aflag;
bool dflag;
bool fflag;
bool lflag;
bool hflag;
};
dirls::dirls()
{
//this->pathQueue = pathQueue;
aflag = false;
dflag = false;
fflag = false;
lflag = false;
hflag = false;
}
dirls::dirls(bool a, bool d, bool f, bool l, bool h)
{
aflag = a;
dflag = d;
fflag = f;
lflag = l;
hflag = h;
}
void dirls::print_usage(string s)
{
cout << "Usage: ";
cout << s;
cout << " [(-[adflh]+) (dir)]*" << endl;
cout << "-a: include dot files" << endl;
cout << "-f: follow symbolic links" << endl;
cout << "-d: only this directory" << endl;
cout << "-l: long form" << endl;
cout << "-h: prints this message" << endl;
}
bool isDir(string dir) // check if an argument is a directory
{
struct stat fileInfo;
stat(dir.c_str(), &fileInfo);
if (S_ISDIR(fileInfo.st_mode))
return true;
else
return false;
}
void dirls::getdir(string dir, vector<string>& files, bool recursive)
{
DIR* dp; //create the directory object
struct dirent* entry; //create the entry structure
dp = opendir(dir.c_str()); //open directory by converting the string to const char*
if (dir.at(dir.length() - 1) != '/') {
dir = dir + "/";
}
if (dp != NULL) { //if the directory isn't empty
while (entry = readdir(dp)) { //while there is something in the directory
if (aflag == false && dflag == false) // if -a is not included then exclude dot files
{
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{ //and if the entry isn't "." or ".."
//if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
}
else if (aflag == true && dflag == false)//if -a included and -d is not included then incude dot files and recurse
{
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
else if (aflag == false && dflag == true) // if -a is not included and -d is included then don't incude dot files and remove recursion
{
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{ //and if the entry isn't "." or ".."
//if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
//getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
}
else if (aflag == true && dflag == true) // if -a is included and -d is included then inclue dot files and remov recursion
{
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
//getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
else
{ };
}
(void)closedir(dp); //close directory
}
else
{
perror("Couldn't open the directory.");
}
}
void dirls::longlisting(string dir, vector<string>& files)
{
string complete;
for (int i = 0; i < files.size(); i++)
{
struct stat buf;
lstat(files[i].c_str(), &buf);
uid_t userId = buf.st_uid;
gid_t groupId = buf.st_gid;
struct passwd* user = getpwuid(userId);
struct group* group = getgrgid(groupId);
string perms = string((S_ISDIR(buf.st_mode)) ? "d" : "-") + ((buf.st_mode & S_IRUSR) ? "r" : "-") + ((buf.st_mode & S_IWUSR) ? "w" : "-") + ((buf.st_mode & S_IXUSR) ? "x" : "-") + ((buf.st_mode & S_IRGRP) ? "r" : "-") + ((buf.st_mode & S_IWGRP) ? "w" : "-") + ((buf.st_mode & S_IXGRP) ? "x" : "-") + ((buf.st_mode & S_IROTH) ? "r" : "-") + ((buf.st_mode & S_IWOTH) ? "w" : "-") + ((buf.st_mode & S_IXOTH) ? "x" : "-");
complete = perms + " " + to_string(buf.st_size) + " " + user->pw_name + " " + group->gr_name + " " + dir;
files[i] = complete + files[i];
}
}
void dirls::initiate(string s, vector<string>& files, vector<string>& paths)
{
while (!paths.empty())
{
char* pathname = (char*)paths.front().c_str();
getdir(paths.front(), files, true);
if (paths.size() > 1)
{
cout << pathname << ":" << endl;
}
if (hflag)
{
print_usage(s);
paths.erase(paths.begin());
continue;
}
if (lflag)
{
longlisting(paths.front(), files);
paths.erase(paths.begin());
continue;
}
if (aflag)
{
paths.erase(paths.begin());
continue;
}
if (dflag)
{
paths.erase(paths.begin());
continue;
}
paths.erase(paths.begin());
}
}
int main(int argc, char* argv[])
{
int opt = 0;
string first = argv[0];
string dir = argv[1];
struct stat buf;
bool a = false, d = false, f = false, l = false, h = false;
vector<string> files = vector<string>(); // holds the files in a directory
vector<string> paths = vector<string>(); // holds the paths
while ((opt = getopt(argc, argv, "adflh")) != -1)
{
switch (opt)
{
case 'a':
a = true;
break;
case 'd':
d = true;
break;
case 'f':
f = true;
break;
case 'l':
l = true;
break;
case 'h':
h = true;
break;
default:
break;
}
}
dirls x = dirls(a, d, f, l, h);
for (int i = optind; i < argc; i++)
{
paths.push_back(argv[i]);
}
if (paths.empty())
{
paths.push_back(".");
}
x.initiate(first, files, paths);
for (int i = 0; i < files.size(); i++)
{
if ((h == true) && (a == false) && (d == false) && (f == false) && (l == false))
break;
cout << files[i] << endl;
}
return 0;
}
I am fairly sure the issue lies in getdir perhaps in my understanding of strcmp so I'll put a copy of that function below for easier viewing.
void dirls::getdir(string dir, vector<string>& files, bool recursive)
{
DIR* dp; //create the directory object
struct dirent* entry; //create the entry structure
dp = opendir(dir.c_str()); //open directory by converting the string to const char*
if (dir.at(dir.length() - 1) != '/') {
dir = dir + "/";
}
if (dp != NULL) { //if the directory isn't empty
while (entry = readdir(dp)) { //while there is something in the directory
if (aflag == false && dflag == false) // if -a is not included then exclude dot files | NOT WORKING
{
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{ //and if the entry isn't "." or ".."
//if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
}
else if (aflag == true && dflag == false)//if -a included and -d is not included then incude dot files and recurse
{
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
else if (aflag == false && dflag == true) // if -a is not included and -d is included then don't incude dot files and remove recursion
{
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{ //and if the entry isn't "." or ".."
//if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
//getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
}
else if (aflag == true && dflag == true) // if -a is included and -d is included then inclue dot files and remov recursion
{
if (isDir(dir + entry->d_name) == true && isDir(dir))
{
files.push_back(string(entry->d_name)); //add entry to the list of files
//getdir(dir + entry->d_name, files, true); //recurse
}
else
{
files.push_back(string(entry->d_name));//add the entry to the list of files
}
}
else
{ };
}
(void)closedir(dp); //close directory
}
else
{
perror("Couldn't open the directory.");
}
}
strcmp compares the whole string, so your function is filtering out exact matches to "." and "..". If you only want to check the first letter of the filename you can use array indexing in the string
entry->d_name[0] != '.'
or the strncmp function which compares only the first of a certain number of characters
strncmp(entry->d_name, ".", 1) != 0
http://www.cplusplus.com/reference/cstring/strncmp/

This program is automatically exiting after finishing any one action, why?

My program is exiting after giving one command every time and I am unable to find a logical reason why. I have checked all my loops and if-statements for exit codes but was not able to located any.
the program includes many classes and functions, but here is main:
int main()
{
int local_location = 0;
vector<string>Inventory = { "", "", "" };
unordered_set<string> excl = { "in", "on", "the", "with" };
string word;
array<string, 2> command;
size_t n = 0;
command.at(1) = "";
command.at(0) = "";
while (n < command.size() && cin >> word) {
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
}
if (command.at(0) == "look") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "get") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "drop") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "bag") {
bag(Inventory);
}
else if (command.at(0) == "go") {
look(command.at(1), local_location, Inventory);
}
}
Loop over standard input and reset the condition on n after processing the command.
while(cin>>word)
{
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
if (n== command.size())
{
// process the command
// reset n=0
}
}

M_construct error when reading file contents

I'm creating a game that requires a lot of setup. I decided to add a configuration file (.ini) and a reader to get the information. My ini file is setup as follows:
-cmd arg0 arg1
I initially only had one command which worked fine until I added a second. For whatever reason, I receive an std::logic_error when my command is not the first one.
// this works
-load w "someName"
// this doesn't
-delete "someName"
Here is the code used to read the file:
InitFileReader::InitFileReader()
{
std::string ini_file_path = "";
ini_file_path += PROGRAM_FOLDER;
ini_file_path += "\\blockgame.ini";
std::ifstream ini_file(ini_file_path);
if (!ini_file.is_open()) std::cout << "Couldn't find configuration file at " << ini_file_path << std::endl;
std::string line;
while(std::getline(ini_file, line))
{
if (starts_with(line, "-load "))
{
std::string arg0 = "";
unsigned int index = 6;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string arg1 = "";
bool reached_quote = false;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ' && !reached_quote) continue;
if (c == '\"' && !reached_quote)
{
reached_quote = true;
continue;
}
else if (c == '\"') break;
arg1 += c;
}
sfr = new SaveFolderReader(arg1);
if (arg0 == "new")
{
sfr->new_header(DEFAULT_HEADER);
}
else if (arg0 == "def")
{
sfr->restore_header(DEFAULT_HEADER);
}
}
else if (starts_with(line, "-delete "))
{
std::string arg0 = "";
unsigned int index = 8;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string world_path = "";
world_path += PROGRAM_FOLDER;
world_path += "\\save\\";
world_path += arg0;
if (rmdir(world_path.c_str()) != 0)
{
std::cout << "Error deleting world \"" << arg0 << "\"" << std::endl;
}
}
}
}
inline bool starts_with(const std::string& target, const std::string& prefix)
{
if (target.size() < prefix.size())
return false;
for (unsigned int i = 0; i < prefix.size(); i++)
{
if (target[i] != prefix[i])
return false;
}
return true;
}
The PROGRAM_FOLDER constant is just the parent folder of the path returned by argv[0] in main. I can't run the debugger on this code because the path changes to something strange when I do that.
I know that this error shows up because of a nullptr initialization of std::string but I still have no idea why this is happening.
I've tried typing in random characters into the config file and get the same result. It baffles me that the first if-statement works fine but the second one doesn't (when I use the -delete command).
Any suggestions would be of great use, thanks in advance!
It turns out that the error wasn't coming from that block of code at all. What was happening was that my game tried to load data in afterwards but because I didn't write the load command there was nothing to read from. I fixed my Debugger issue (For whatever reason the char[] I allocated stored different data when the debugger ran) and just reverted to std::strings.

Find file with wildcards on entire disk

I need to find a variable extension file using wildcards (*.txt, *.jpeg, *.doc) on a disk (c:).
I tried with the following function, but I can't make it recursive, and it's not working:
void Recurse(LPCTSTR str)
{
WIN32_FIND_DATA file;
cout << "Value INPUT:" << str <<"\n";
HANDLE search_handle=FindFirstFile(str,&file);
if (search_handle) {
do {
if(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
strcmp(file.cFileName,"..")!=0
&& strcmp(file.cFileName,".")!=0
&& strcmp(file.cFileName,"$Recycle.Bin")!=0
&& strcmp(file.cFileName,"Recovery")!=0
&& strcmp(file.cFileName,"System Volume Information")!=0
&& strcmp(file.cFileName,"PerfLogs")!=0
&& strcmp(file.cFileName,"Windows")!=0)
{
str = file.cFileName;
cout << "Directory :" << file.cFileName <<"\n";
Recurse(str); // Function to remind new directory
} else {
if (file.cFileName == "*.txt") {
std::wcout << file.cFileName << std::endl; //Print files find with estension txt
}
}
} while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
}
Of course I tried it with a static value (*.txt) to see if it worked, but it didn't work when I called it from in main:
Recurse("C:\\*");
I modified the code in this way. If it finds them throwing me * .txt files and me brings them correctly, but the path instead in many files shows me incorrect with several strange characters. I can not understand why such behavior.
char *my1;
char *my2;
char *my3;
char *my4;
char *cp2;
LPCTSTR ori;
std::string stringa_mia;
std::vector<std::string> listafiles;
std::vector<std::string> listapath;
void Recurse(LPCTSTR str, LPCTSTR ori)
{
WIN32_FIND_DATA file;
cp2 = strdup(str);
strcat(cp2, "\\*");
HANDLE search_handle=FindFirstFile(cp2,&file);
BOOL res = TRUE;
if (search_handle)
{
while(search_handle != INVALID_HANDLE_VALUE && res)
{
if(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
strcmp(file.cFileName,"..")!=0
&& strcmp(file.cFileName,".")!=0
&& strcmp(file.cFileName,"$Recycle.Bin")!=0
&& strcmp(file.cFileName,"Recovery")!=0
&& strcmp(file.cFileName,"System Volume Information")!=0
&& strcmp(file.cFileName,"PerfLogs")!=0
&& strcmp(file.cFileName,"Windows")!=0
&& strcmp(file.cFileName,"Program Files")!=0
&& strcmp(file.cFileName,"Boot")!=0
&& strcmp(file.cFileName,"Program Files (x86)")!=0
&& strcmp(file.cFileName,"AppData")!=0
&& strcmp(file.cFileName,"ProgramData")!=0
&& strcmp(file.cFileName,"Cookies")!=0
&& strcmp(file.cFileName,".android")!=0
&& strcmp(file.cFileName,"Programmi")!=0
)
{
my3 = strdup(file.cFileName);
my2 = strdup(str);
my1 = strdup(ori);
strcat(my2, "\\");
strcat(my2, my3);
CloseHandle(search_handle);
Recurse(my2,ori);
}
else
{
my4 = strdup(file.cFileName);
stringa_mia = std::string(my4);
if (stringa_mia.find(".txt")!=std::string::npos) {
listafiles.push_back(stringa_mia);
listapath.push_back(str);
}
}
res = FindNextFile(search_handle,&file);
}
CloseHandle(search_handle);
}
}
i call the function in this mode:
Recurse("C:","C:");