В вашем коде есть несколько проблем:
- Вы должны проверить фактическое количество аргументов, предоставленных в командной строке, чтобы избежать неопределенного поведения, если было предоставлено менее 3.
fopen(v[3], "W");
использует недопустимую строку режима, вы должны использовать "w"
.Непонятно, для чего этот указатель потока используется в любом случае. dir1
и dir2
не тестируются: у вас неопределенное поведение при сбое opendir()
. Вызывается stat
с именем записи каталога, которое не является относительным путем к файлу, если каталог отличается от текущего каталога.Вы должны составить имя пути из имени каталога и имени записи. if (filesize1.st_size == filesize2.st_size);
имеет дополнительный ;
в конце строки, в результате чего следующий блок выполняется безоговорочно.Вы должны использовать K&R style with
{`в конце строки, чтобы избежать таких глупых ошибок. - логика параллельного сканирования неверна: вы должны заново открыть или, по крайней мере, перемотать второй каталог для каждой записи в первомдля полного сканирования возможных совпадений.
Вот исправленная версия:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
char *buildpath(char *dest, size_t size, const char *dir, const char *name) {
size_t len = strlen(dir);
const char *sep = "";
if (len > 0 && dir[len - 1] != '/')
sep = "/";
if ((unsigned)snprintf(dest, size, "%s%s%s", dir, sep, name) < size)
return dest;
else
return NULL;
}
int main(int argc, char *argv[]) {
char path1[1024];
char path2[1024];
struct dirent *dp1;
struct dirent *dp2;
DIR *dir1;
DIR *dir2;
struct stat filesize1;
struct stat filesize2;
if (argc < 3) {
fprintf(stderr, "missing argument\n");
fprintf(stderr, "usage: cmpdir dir1 dir2\n");
return 1;
}
dir1 = opendir(argv[1]);
if (dir1 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[1], strerror(errno));
return 1;
}
dir2 = opendir(argv[2]);
if (dir2 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[2], strerror(errno));
return 1;
}
while ((dp1 = readdir(dir1)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp1->d_name, ".")
|| !strcmp(dp1->d_name, ".."))
continue;
if (!buildpath(path1, sizeof path1, argv[1], dp1->d_name)) {
/* path too long */
continue;
}
if (stat(path1, &filesize1)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize1.st_mode)) {
/* not a regular file */
continue;
}
rewinddir(dir2);
while ((dp2 = readdir(dir2)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp2->d_name, ".")
|| !strcmp(dp2->d_name, ".."))
continue;
if (!buildpath(path2, sizeof path2, argv[2], dp2->d_name)) {
/* path too long */
continue;
}
if (stat(path2, &filesize2)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize2.st_mode)) {
/* not a regular file */
continue;
}
if (filesize1.st_size == filesize2.st_size) {
printf("%s and %s have the same size %llu\n",
path1, path2, (unsigned long long)filesize1.st_size);
/* perform actual comparison... */
}
}
}
closedir(dir1);
closedir(dir2);
return 0;
}