Trying to understand why unlink isn't working (not removing the file) in my code down below. The only thing I can imagine is that the program thinks I'm still interacting with the file so its not actually unlinking it since its still in use. The code is meant to be a copy of "rm"
void directorySearch(const char *dName)
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir (dName)) != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
if ( ent->d_type!=DT_DIR)
{
//Where the crazy happens
printf ("%s\n", ent->d_name);
char path[PATH_MAX];
const char * d_name = ent->d_name;
unlink(path);
}
if ( ent->d_type==DT_DIR && strcmp(ent->d_name, ".")!= 0 && strcmp(ent->d_name, "..") != 0)
{
int path_length;
char path[PATH_MAX];
const char * d_name = ent->d_name;
path_length = snprintf (path, PATH_MAX, "%s/%s", dName, d_name);
directorySearch(path);
}
}
closedir (dir);
}
else
{
cout << "error with "<< dName<< endl;
}
}
Edited with unlink instead of remove, although both don't work...
You have declared your path variable, but not actually copied anything into that variable. So that's a problem. Also, as a matter of course you should examine the return value from unlink, and if less than zero, examine errno to determine the exact nature of the error. (Typically permissions on no such file.)
Related
I have to make a project which asks me to create a program that will compile a C project by recursively descending into directories and launching processes which compile a file of code by calling GCC and look through directories and launch a new process for every ".c" file in the current directory that process will call gcc on the .c file making a .o file.
I have written this code so far to list the directories first
I am having trouble checking what files are .c and how to convert them to .o
can someone help me with some relevant information/links that I can refer to?
void listdir(const char *name, int indent)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR) {
char path[1024];
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
printf("%*s[%s]\n", indent, "", entry->d_name);
listdir(path, indent + 2);
} else {
printf("%*s- %s\n", indent, "", entry->d_name);
}
}
closedir(dir);
}
int main(void) {
listdir(".", 0);
return 0;
}
You will need to use fork() and exec() in order to get a .o file it should look something like this
if ((forkmefool[i] = fork()) < 0)
{
printf("no Procceses");
exit(0);
}
else if (forkmefool[i] == 0)
{
char *args[] = {"cc", entry->d_name, "-c", NULL};
execv("/usr/bin/cc", args);
}
take a note of exec()
I am new to programming.I want to access all the directories and sub-directories from default installed directory,but it is failing in traversing the folder, here i am passing path to constant char.Below is the code
using namespace std;
int reading(const char *d_path)
{
cout<<"In Reading"<<endl;
/*bfs::path pathSource("c:\\Program Files\\");*/
struct stat info; //
DIR *dir;
struct dirent *ent;
dir= opendir (d_path);
cout<<dir<<endl;
if ((dir = opendir (d_path)) != NULL)
{
cout<<"in IF"<<endl;
while ((ent = readdir (dir)) != NULL)
{
if (ent->d_name[0] != NULL)
{
cout<<"New"<<endl;
string path = string (d_path) + string(ent->d_name) + '\\' ;
cout<< "Entry = "<<path<<endl;
stat (path,&info);
if(S_ISDIR(info.st_mode))
{
reading(path);
}
}
}
closedir (dir);
}
/* print all the files and directories within directory */
else
{
/* could not open directory */
perror ("");
}
return 0;
}
Use the string::c_str() method, like stat(path.c_str()), to convert a C++ string to a C string.
See http://cplusplus.com/reference/string/string/c_str/ for more information.
I have a C program that finds duplicate files within a directory. The program is executed on the command line and passed 2 arguments. One is the parent directory, and argument two is the file name. It is working code in c, but I have a GUI and other files for "microservices" written in c++.
How would one call this C code from a c++ file?
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
//Compile: gcc dreamduplicatefinder.c -o dreamduplicatefinder.exe
//Run: ./dreamduplicateFinder.exe parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//printf(dir); //error could becuase trying to open shortcut or corrupt folder.
printf("%s\n",path);
perror("Failed to open directory");
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("%s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
//Step 2...
//size matches, files can be same; confirm it by matching both file contents...
int fdOriginal = open(originalFile, O_RDONLY);
int fdCurr = open(currFile, O_RDONLY);
if (fdOriginal == -1 || fdCurr == -1)
return false; //error occurred, not sure if file is duplicate...
//we will read file in small chunks and compare...
int chunkSize = 1024, bytesRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
while (true)
{
//read file in chunk...
bytesRead = read(fdOriginal, bufferOriginal, chunkSize);
if (bytesRead <= 0)
break; //end of file...
bytesRead = read(fdCurr, bufferCurr, bytesRead);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
My errors include: (from compareFiles function)
2x 'open' identifier not found
2x 'read' identifier not found
The working code for those curious.
Thank you #MarcusMüller & #JesperJuhl
#include "stdafx.h" //there is nothing in this header
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Compile: gcc <name of this file>.cpp -o <nameOfThisFile>.exe
//Run: <nameOfThisFile> parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//possibly trying to open shortcut or corrupt folder typically.
printf("Failed to open directory %s \n",path);
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("This is a duplicate! %s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
FILE* fdOriginal;
if (fdOriginal = fopen(originalFile, "r")) {
if (fdOriginal == NULL) { fputs("File error", stderr); return false; }
}
else return false; //error occurred, not sure if duplicate
FILE* fdCurr;
if (fdCurr = fopen(currFile, "r")) {
if (fdCurr == NULL) { fputs("File error", stderr); return false; }
}
else return false;
int chunkSize = 1024, objsRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
if (bufferOriginal == NULL) { fputs("Memory error for buff orig", stderr); exit(2); }
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
if (bufferCurr == NULL) { fputs("Memory error for buff curr", stderr); exit(2); }
while (true)
{
//read file in chunk...
//std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE* stream );
objsRead = fread(bufferOriginal, sizeof(char), chunkSize , fdOriginal);
if (objsRead <= 0)
break; //end of file...
objsRead = fread(bufferCurr, sizeof(char), objsRead, fdCurr);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
You usually just wouldn't do that. You'd wrap it in a C function, and compile it to an object file.
Then you'd include your C header with extern "C" {…}, and just call that function from C++.
When building your executable, you'd link in the object file containing your C function. Done!
Note: C isn't C++, and albeit your code not being illegal in C++ (as far as I can instantly tell), it does very "ugly" things (like #defineing true and false – ugh, that would already be a bad idea in C, to be honest). So, deal with it like you would deal with code in Fortran, or Java, or any other language that has a calling convention that you can use from C++ (which, usually, is the C calling convention): Just use it as an extern object.
Using ::open and ::read should cause the functions to be found.
You may also want to replace the C headers (like "string.h") with their C++ equivalent versions (like "cstring").
Your defines for true and false should also go. In C++ those are proper bools, not integers. This means the return type of CompareFiles should be changed to bool.
And you should wrap duplicateCount in an anonymous namespace - or return it from the function that updates it (either by returning a small struct with two ints, or by using a std::pair or std::tuple) - global variables are evil.
This program is printing the directories at the root level
Directory_1
Directory_2
but I want to be able to print the directories within them too
Directory_1
Directory_1_2
Directory_1_3
Directory_2
Directory 2_1
Directory_2_1_1
Directory_4
I am trying to do it recursively but I am finding it hard to pass the Directory_1 as a root so it gets evaluated.. What am i missing?
Here is my output
..
.
Directory_1
Directory_2
Failed to open directory: No such file or directory
Code
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
char *arg_temp;
int printDepthFirst(char *arg_tmp);
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
arg_temp = argv[1];
printDepthFirst(arg_temp);
}
int printDepthFirst(char *arg_tmp)
{
struct dirent *direntp;
DIR *dirp;
if ((dirp = opendir(arg_tmp)) == NULL) {
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
{
printf("%s\n", direntp->d_name);
arg_tmp = direntp->d_name;
}
printDepthFirst(arg_tmp);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
Now, I know some people get irritated when asking questions that they think I am expecting them to code this, you dont need to, if you can tell me theoretically what i need to do.. I will research it although if its a small programmatically fix and you can post that I would really appreaciate it.. but if not.. I would also love to hear about what needs to be done in words..
Thank you
Well this should help:
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
static int display_info(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf)
{
switch(tflag)
{
case FTW_D:
case FTW_DP: puts(fpath); break;
}
return 0; /* To tell nftw() to continue */
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
if (nftw(argv[1], display_info, 20, flags) == -1)
{
perror("nftw");
return 255;
}
return 0;
}
Have a look at what fields struct dirent contains.
The string dirent::d_name is a name of a directory, not it's full path. So, if your directory "C:\Alpha" contains directory "C:\Alpha\Beta", d_name would only contatin "Beta", not "C:\Alpha\Beta". You will have to assemble the full path yourself - appending slash/backslash to your arg_tmp and then appending new directory name, like this:
while ((direntp = readdir (dirp)) != NULL)
{
char *dirname = direntp->d_name;
// Only work with directories and avoid recursion on "." and "..":
if (direntp->d_type != DT_DIR || !strcmp (dirname, ".") || !strcmp (dirname, "..")) continue;
// Assemble full directory path:
char current [strlen (arg_tmp) + 2 + strlen (dirname)];
strcpy (current, arg_tmp);
strcat (current, "\\"); // Replace "\\" with "/" on *nix systems
strcat (current, dirname);
// Show it and continue:
printf ("%s\n", current);
printDepthFirst (current);
}
Also, you should call recursively inside the loop, not outside.
Inside your while loop inside printDepthFirst you might need something like:
if(direntp->d_type == DT_DIR)
printDepthFirst(directp->d_name);
You might perhaps have to worry about .. directories too.
Alternatively, I've found boost::filesystem to work quite well.
HI...Can any one provide me the code for how to copy the folder from one directory to another...i am able to copy the files by this code but i cannot copy the entir folder at a time...
FILE *in, *out;
char ch;
if((in=fopen(sour->getfilepath(), "rb")) == NULL)
{
printf("Cannot open input file.\n");
getch();
exit(1);
}
if((out=fopen(dest->getfilepath(), "wb")) == NULL)
{
printf("Cannot open output file.\n");
getch();
exit(1);
}
while(!feof(in))
{
ch = getc(in);
if(ferror(in))
{
printf("Read Error");
clearerr(in);
break;
}
else
{
if(!feof(in)) putc(ch, out);
if(ferror(out))
{
printf("Write Error");
clearerr(out);
break;
}
}
}
fclose(in);
fclose(out);
If you want to do this with portable code, you should probably look into using the Boost filesystem library. For slightly less portability, you can probably use the Posix directory functions (opendir, readdir, closedir, chdir, etc.) If you don't care about portability at all, you may have something system-specific to use (e.g. on Windows FindFirstFile, FindNextFile, FindClose, SetCurrentDirectory).
As far as the actual file copying goes, your code probably won't work very well in real life -- for example, you usually don't report a problem with opening a file right where you tried to open it. Depending on the kind of program involved, you might write that to a log or show it in a status window. Even if you take command-line use for granted, it should still almost certainly be written to stderr, not stdout.
The code is also pretty much pure C. In C++, you can make it a bit more compact:
std::ifstream in(sour->GetFilePath());
std::ofstream out(dest->GetFilePath());
out << in.rdbuf();
Right now, this ignores errors -- there are a number of ways of handling those (e.g. enabling exceptions in the iostreams) so it's hard to show code for that without knowing what you really want.
Shiva, I don't believe that there is a standard library function to do this. I think you have to recursively iterate and create directories and copy files as you go. I'd bet you can find source code that does this on code.google.com or www.krugle.com
i am not really familiar with c++ but maybe you can create the to-be-copied folder in your destination dir, and copy to that folder all the files... i guess you can achieve what you want that way... i just feel there is no built-in routine in c++ that can do that, i mean like in java if i'm not mistaken, you can only copy individual files... i hope i'm not wrong.. just a thought...
what about system calls like system(command).
The C++ standard libraries do not support folder operations. But you should have a look into Boost.FileSystem which enabled the functionality in a cross-platform fashion.
I think a good starting point is this example.
#include <iostream>
#include <string>
#include <fstream>
#include <dirent.h>
void copyFile(const char* fileNameFrom, const char* fileNameTo){
char buff[BUFSIZ];
FILE *in, *out;
size_t n;
in = fopen(fileNameFrom, "rb");
out = fopen(fileNameTo, "wb");
while ( (n=fread(buff,1,BUFSIZ,in)) != 0 ) {
fwrite( buff, 1, n, out );
}
}
int dir(std::string path){
DIR *dir;
struct dirent *ent;
if ((dir = opendir (path.c_str())) != NULL) {
while ((ent = readdir (dir)) != NULL) { /* print all the files and directories within directory */
if (ent->d_name != std::string(".")){ //REMOVE PWD
if (ent->d_name != std::string("..")){ //REMOVE PARENT DIR
std::cout << path << "\\" << ent->d_name << std::endl;
}
}
}
std::cout << std::endl;
closedir (dir);
}else{
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
return 0;
}
int copyAllFiles(std::string sorc, std::string dest){
DIR *dir;
struct dirent *ent;
if ((dir = opendir (sorc.c_str())) != NULL) {
while ((ent = readdir (dir)) != NULL) { /* print all the files and directories within directory */
if (ent->d_name != std::string(".")){ //REMOVE PWD
if (ent->d_name != std::string("..")){ //REMOVE PARENT DIR
std::string copy_sorc = sorc + "\\" + ent->d_name;
std::string copy_dest = dest + "\\" + ent->d_name;
std::cout << "cp " << copy_sorc << " -> " << copy_dest << std::endl;
copyFile(copy_sorc.c_str(), copy_dest.c_str());
}
}
}
std::cout << std::endl;
closedir (dir);
}else{
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
return 0;
}
int main(int argc, char* argv[]){
//dir("C:\\example"); //SHOWS CONTENT IN FOLDER
copyAllFiles("C:\\example", "C:\\destination"); //COPY FOLDER'S CONTENT
return 0;
}