我正在开发一个相当简单的程序,它应该打印出一个给定路径的文件树。该程序只使用直接递归,但当我修改它以分叉一个新的子进程迭代每个新目录时,我开始得到一些奇怪的输出。似乎允许进程向后移动到其父目录。
我一直在名为test的小样本文件夹上测试它。测试包含2个文件(testFile1和testFile2)和一个文件夹(testSub)。文件夹testSub只包含2个文件(testSubFile1和testSubFile2)。据我所知,应该遍历testSub文件夹的子进程正在执行该操作,然后将目录移动到测试文件夹并迭代它。
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
int recFork(char *path){
/*int key = rand() % 113;
printf("--------\n--------\n");
printf("New function\n");
printf("Key: %d\n", key);
printf("path: %s\npid: %d\n", path, getpid());
printf("--------\n--------\n");*/
int status;
pid_t pID = 1;
char name[1024];
struct stat statbuf;
if(stat(path, &statbuf) == -1)
return -1;
/* if the item is a file */
if(S_ISREG(statbuf.st_mode)){
printf("pID: %d ", getpid());
printf("%s\t%8ld\n", path, statbuf.st_size);
}
/* if the item is a directory */
else if((statbuf.st_mode & S_IFMT) == S_IFDIR){
pID = fork();
if(pID > 0){ //parent
//printf("Forked child with pID: %d\n", pID);
waitpid(pID, &status, WUNTRACED);
//printf("Killed: %d\n", pID);
}
else if(pID == 0){ //child
//printf("Child: %d\n", getpid());
DIR *dir;
struct dirent *dp = NULL;
if ((dir = opendir(path)) == NULL){
printf("Cannot open %s\n", path);
exit(EXIT_FAILURE);
}
else{
printf("DIR: %s/\n", path);
while((dp = readdir(dir)) != NULL){
//printf("pID: %d key: %d dp = %s\n", getpid(), key, dp->d_name);
if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue;
sprintf(name, "%s/%s", path, dp->d_name);
//printf("Process: %d Key: %d\n", getpid(), key);
//printf("I was passed: %s\n", path);
//printf("Calling recFork(%s)\n\n", name);
recFork(name);
}
closedir(dir);
}
}
else{ //failed to fork
printf("Failed to fork\n");
exit(EXIT_FAILURE);
}
}
//printf("Returning from : %d with key: %d\n", getpid(), key);
return 0;
}
代码包含了一些注释掉的printf语句,我用它来尝试调试正在发生的事情。老实说,我只是不知所措,我不知道还有谁问。我真的很想知道我做错了什么,所以如果有人能指出我正确的方向,我会非常感激。
答案 0 :(得分:2)
可能发生的事情是readdir()
按照文件系统出来的顺序读取文件,这与ls
显示事物的方式无关。 readdir()
是原始/未排序的输出,而默认情况下ls
按名称排序所有内容。
e.g。你的磁盘文件结构可能是这样的:
./test/.
./test/..
./test/testFile1
./test/testSub/.
./test/testSub/..
./test/testFile2
由于readdir按照存储在目录列表中的顺序返回所有内容,因此您将.
,然后..
,testFile
,testSub
,递归到test
,然后返回主testFile2
目录并继续exit()
。
请注意,您没有检查文件类型。您将尝试对实际文件执行opendir()调用,这将失败,并导致该特定进程stat
。您应该检查由{{1}}返回的文件类型,并且只在它实际上是目录时执行递归调用。
答案 1 :(得分:0)
我明白了!
这个问题是因为一个孩子在递归语句中被分叉了x个级别,虽然我知道每个孩子与其父级相同,但我并不认为这个孩子在自己的递归堆中会有x级深度。
在孩子返回之前,它必须循环退出所有递归调用。我通过在exit(EXIT_SUCCESS);
语句之后添加语句closedir(dir);
解决了这个问题,因此它不会返回所有级别的递归,只要它完成自己的目录就会退出。
感谢大家的帮助!