I dont know why but I am not finding where the problem is. I run a test to see if it is a directory or a file and even the files get considered as folders.
The problem is that while running the loop even for the files it goes into the directory process and postrs " file1 for directories"
Here is the code:
void copie_dossier(char *doss1, char *doss2) {
struct dirent *dptr;
DIR *dp;
struct stat stbuf;
char newDest[strlen(doss2) + 1];
char tempSrc[strlen(doss1) + 1];
strcat(doss2, "/");
strcat(doss1, "/");
strcpy(newDest, doss2);
strcpy(tempSrc, doss1);
stat(doss1, &stbuf);
dp = opendir(doss1);
/*
if (!dp) {
perror("open_dir");
exit(1);
}
*/
if (!(dp))
return;
if (!(dptr = readdir(dp)))
return;
int mk = mkdir(doss2, 0777);
if (mk == -1) {
perror("create_dir");
exit(1);
}
while ((dptr = readdir(dp)) != NULL) {
struct stat stbuf2;
//stat(dptr->d_name, &stbuf2);
char *new = dptr->d_name;
if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) {
continue;
}
if (!stat(tempSrc, &stbuf2)) {
if (S_ISREG(stbuf.st_mode)) {
printf("%s for files\n", dptr->d_name);
strcat(newDest, dptr->d_name);
strcat(tempSrc, dptr->d_name);
copy_files(tempSrc, newDest);
strcpy(newDest, doss2);
strcpy(tempSrc, doss1);
}
if (S_ISDIR(stbuf.st_mode)) {
printf("%s for directory \n", dptr->d_name);
strcat(newDest, dptr->d_name);
strcat(tempSrc, dptr->d_name);
copie_dossier(tempSrc, newDest);
strcpy(newDest, doss2);
strcpy(tempSrc, doss1);
}
}
}
closedir(dp);
}
The problem is in the allocation of the local buffers:
char newDest[strlen(doss2) + 1];
char tempSrc[strlen(doss1) + 1];
strcat(doss2, "/");
strcat(doss1, "/");
strcpy(newDest, doss2);
strcpy(tempSrc, doss1);
Even the very first use of newDest
and tempSrc
invoke undefined behavior as you copy strings that do not fit in the destination. newDest
and tempSrc
are allocated for exactly the number of characters in doss1
and doss2
respectively (ad the final '\0'
), but you append an extra /
before copying.
Later in the code, you concatenate directory entry names, causing further undefined behavior.
You must change the logic for pathname composition. You can use memory allocation or a global buffer in which you concatenate the entries while remembering where the pathname used to end to strip it back to the previous state.
There is another big issue in your test for directory / filename: You do not stat()
the proper pathname and you use a separate stbuf2
instead of the stbuf
. You should first create the pathname to the current entry, pass it to stat()
and check for directory and filename on the resulting stbuf
.
Here is an improved version:
char *make_path(const char *path, const char *name) {
size_t len = strlen(path);
char *p = malloc(len + 1 + strlen(name) + 1);
if (p) {
strcpy(p, path);
p[len] = '/';
strcpy(p + len + 1, name);
}
return p;
}
void copie_dossier(const char *doss1, const char *doss2) {
DIR *dp;
struct dirent *dptr;
dp = opendir(doss1);
if (dp == NULL)
return;
int mk = mkdir(doss2, 0777);
if (mk == -1) {
perror("create_dir");
exit(1);
}
while ((dptr = readdir(dp)) != NULL) {
struct stat stbuf;
char *source, *dest;
if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) {
continue;
}
source = makepath(doss1, dptr->d_name);
dest = makepath(doss2, dptr->d_name);
if (!source || !dest) {
perror("makepath");
exit(1);
}
if (!stat(source, &stbuf)) {
if (S_ISREG(stbuf.st_mode)) {
printf("%s for files\n", dptr->d_name);
copy_files(source, dest);
} else
if (S_ISDIR(stbuf.st_mode)) {
printf("%s for directory \n", dptr->d_name);
copie_dossier(source, dest);
}
} else {
// should issue a diagnostic message
}
free(source);
free(dest);
}
closedir(dp);
}
You did not post the code for function copy_files
. I assume it copies one file, despite the name.