使用C删除非空目录时出现段错误
Segfault when deleting non-empty directory using C
我正在尝试删除一个 none 空目录,无需系统调用且无需使用大量库。到目前为止我的代码是...
int rmrf(char *path) {
char* path_copy = (char *) malloc(1024 * sizeof(char));
strcpy(path_copy, path);
DIR *directory = opendir(path_copy);
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { //skip /. and /..
} else if (entry->d_type == DT_DIR) { //directory recurse
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else { //file delete
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
remove(path_copy);
}
entry = readdir(directory);
}
closedir(directory);
return 0;
}
我当前的文件结构是这样的...
Who
|---Region 1
|---County 1
|---SubCounty 1
|---County 2
|---Region 2
|---County 1
|---Region 3
目前我遇到段错误,但随着时间的推移出现在不同的地方。今天早些时候,我将深入了解两层递归,然后将错误排除在外,但截至目前,我什至无法通过一个完整的层级。我不知道哪里出了问题,当我使用 gdb 调查问题时,我得到...
malloc.c: No such file or directory.
如有任何帮助,我们将不胜感激!
更新:
我采纳了 paxdiablo 的建议并提出了结果函数...
int rmrf(char *path) {
char* path_copy = malloc(1024);
DIR *directory = opendir(path);
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { //skip /. and /..
} else if (entry->d_type == DT_DIR) { //directory recurse
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else { //file delete
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
remove(path_copy);
}
entry = readdir(directory);
}
closedir(directory);
free(path_copy);
return 0;
}
但是我仍然遇到段错误,尽管它在递归中越来越远。段错误的 gdb 输出如下...
Program received signal SIGSEGV, Segmentation fault.
_int_malloc (av=av@entry=0x7ffff7dd1b20 <main_arena>, bytes=bytes@entry=32816) at malloc.c:3802
3802 malloc.c: No such file or directory.
(gdb) where
#0 _int_malloc (av=av@entry=0x7ffff7dd1b20 <main_arena>, bytes=bytes@entry=32816) at malloc.c:3802
#1 0x00007ffff7a91184 in __GI___libc_malloc (bytes=32816) at malloc.c:2913
#2 0x00007ffff7ad51ba in __alloc_dir (statp=0x7fffffffe190, flags=0, close_fd=true, fd=6) at ../sysdeps/posix/opendir.c:247
#3 opendir_tail (fd=6) at ../sysdeps/posix/opendir.c:145
#4 __opendir (name=<optimized out>) at ../sysdeps/posix/opendir.c:200
#5 0x0000000000401bca in rmrf ()
#6 0x0000000000401c8d in rmrf ()
#7 0x0000000000401c8d in rmrf ()
#8 0x0000000000402380 in main ()
想法?
对于您的初始代码,您在进入函数时执行一次:
strcpy(path_copy, path);
然后对当前目录中的每个个文件或目录执行此操作:
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
这意味着,如果您的当前目录 /xx
中有文件 a
、b
和 c
,则 path_copy
变量将循环:
/xx/a /xx/a/b /xx/a/b/c
而不是正确的:
/xx/a /xx/b /xx/c
如果文件数量足够多,您将很容易耗尽为路径分配的 1024 字节。
如果你想解决这个问题,那么你应该每次都从头开始这个变量:
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) {
if (entry->d_type == DT_DIR) {
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else {
sprintf(path_copy, "%s/%s", path, entry->d_name);
remove(path_copy);
}
}
您会注意到我已经稍微修改了您的初始条件,使其更有意义(如果文件既不是 .
也不是 ..
,则只执行内部位)。
我还在 else
子句中展示了使用 sprintf
而不是一组 strcpy/strcat
调用来构建要删除的字符串的更短方法。如果您愿意,也可以在 if
子句中随意执行此操作,我使用旧方法保留它,因此您可以看到您需要做的就是添加初始路径。
还有一些额外的要点,适用于您的第一个 and/or 第二个代码片段:
您还应该确保释放您在每个级别分配的内存,紧接在return从函数之前,closedir()
和 return
.
你永远不会需要转换malloc
的return值,因为void *
可以隐式转换为任何其他类型的指针。事实上,这样做很危险,因为它可以隐藏某些细微的错误。
同样,您 永远 不需要乘以 sizeof(char)
- 也就是说,根据定义,总是乘以一个。
您可以将 path_copy
的创建移动到 之前 file/directory 检查,因为它对两个部分都是通用的。
最后,如果您正在处理的目录实际上不存在,您将遇到麻烦,因为 opendir
将 return NULL,您将立即尝试将其传递给 readdir
.
考虑到所有这些,我将从以下程序开始,该程序实际上 遍历 树并打印出它找到的所有文件。一旦你对此感到满意,你可以在删除的位中添加回来:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int rmrf(char *path) {
char *path_copy = malloc(1024);
DIR *directory = opendir(path);
if (directory != NULL) {
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) {
sprintf(path_copy, "%s/%s", path, entry->d_name);
if (entry->d_type == DT_DIR) {
rmrf(path_copy);
puts(path);
} else {
puts(path_copy);
}
}
entry = readdir(directory);
}
closedir(directory);
}
free(path_copy);
return 0;
}
主要代码只是一个驱动程序,用于确保正确设置思想。只要确保在 运行ning 之前,您没有(在当前目录中)要保留的 paxtest
或 paxtest2
文件或目录。
int main(void) {
system("rm -rf paxjunk");
system("mkdir paxjunk");
system("touch paxjunk/0.txt");
system("mkdir paxjunk/1");
system("touch paxjunk/1/1.txt");
system("mkdir paxjunk/2");
system("touch paxjunk/2/2.txt");
rmrf("paxjunk");
puts("===");
system("rm -rf paxjunk2");
rmrf("paxjunk2");
puts("===");
system("rm -rf paxjunk");
return 0;
}
当你运行这个时,你应该看到它工作正常:
paxjunk/0.txt
paxjunk/1/1.txt
paxjunk
paxjunk/2/2.txt
paxjunk
===
===
我正在尝试删除一个 none 空目录,无需系统调用且无需使用大量库。到目前为止我的代码是...
int rmrf(char *path) {
char* path_copy = (char *) malloc(1024 * sizeof(char));
strcpy(path_copy, path);
DIR *directory = opendir(path_copy);
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { //skip /. and /..
} else if (entry->d_type == DT_DIR) { //directory recurse
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else { //file delete
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
remove(path_copy);
}
entry = readdir(directory);
}
closedir(directory);
return 0;
}
我当前的文件结构是这样的...
Who
|---Region 1
|---County 1
|---SubCounty 1
|---County 2
|---Region 2
|---County 1
|---Region 3
目前我遇到段错误,但随着时间的推移出现在不同的地方。今天早些时候,我将深入了解两层递归,然后将错误排除在外,但截至目前,我什至无法通过一个完整的层级。我不知道哪里出了问题,当我使用 gdb 调查问题时,我得到...
malloc.c: No such file or directory.
如有任何帮助,我们将不胜感激!
更新:
我采纳了 paxdiablo 的建议并提出了结果函数...
int rmrf(char *path) {
char* path_copy = malloc(1024);
DIR *directory = opendir(path);
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { //skip /. and /..
} else if (entry->d_type == DT_DIR) { //directory recurse
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else { //file delete
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
remove(path_copy);
}
entry = readdir(directory);
}
closedir(directory);
free(path_copy);
return 0;
}
但是我仍然遇到段错误,尽管它在递归中越来越远。段错误的 gdb 输出如下...
Program received signal SIGSEGV, Segmentation fault.
_int_malloc (av=av@entry=0x7ffff7dd1b20 <main_arena>, bytes=bytes@entry=32816) at malloc.c:3802
3802 malloc.c: No such file or directory.
(gdb) where
#0 _int_malloc (av=av@entry=0x7ffff7dd1b20 <main_arena>, bytes=bytes@entry=32816) at malloc.c:3802
#1 0x00007ffff7a91184 in __GI___libc_malloc (bytes=32816) at malloc.c:2913
#2 0x00007ffff7ad51ba in __alloc_dir (statp=0x7fffffffe190, flags=0, close_fd=true, fd=6) at ../sysdeps/posix/opendir.c:247
#3 opendir_tail (fd=6) at ../sysdeps/posix/opendir.c:145
#4 __opendir (name=<optimized out>) at ../sysdeps/posix/opendir.c:200
#5 0x0000000000401bca in rmrf ()
#6 0x0000000000401c8d in rmrf ()
#7 0x0000000000401c8d in rmrf ()
#8 0x0000000000402380 in main ()
想法?
对于您的初始代码,您在进入函数时执行一次:
strcpy(path_copy, path);
然后对当前目录中的每个个文件或目录执行此操作:
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
这意味着,如果您的当前目录 /xx
中有文件 a
、b
和 c
,则 path_copy
变量将循环:
/xx/a /xx/a/b /xx/a/b/c
而不是正确的:
/xx/a /xx/b /xx/c
如果文件数量足够多,您将很容易耗尽为路径分配的 1024 字节。
如果你想解决这个问题,那么你应该每次都从头开始这个变量:
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) {
if (entry->d_type == DT_DIR) {
strcpy(path_copy, path);
strcat(path_copy, "/");
strcat(path_copy, entry->d_name);
rmrf(path_copy);
remove(path);
} else {
sprintf(path_copy, "%s/%s", path, entry->d_name);
remove(path_copy);
}
}
您会注意到我已经稍微修改了您的初始条件,使其更有意义(如果文件既不是 .
也不是 ..
,则只执行内部位)。
我还在 else
子句中展示了使用 sprintf
而不是一组 strcpy/strcat
调用来构建要删除的字符串的更短方法。如果您愿意,也可以在 if
子句中随意执行此操作,我使用旧方法保留它,因此您可以看到您需要做的就是添加初始路径。
还有一些额外的要点,适用于您的第一个 and/or 第二个代码片段:
您还应该确保释放您在每个级别分配的内存,紧接在return从函数之前,
closedir()
和return
.你永远不会需要转换
malloc
的return值,因为void *
可以隐式转换为任何其他类型的指针。事实上,这样做很危险,因为它可以隐藏某些细微的错误。同样,您 永远 不需要乘以
sizeof(char)
- 也就是说,根据定义,总是乘以一个。您可以将
path_copy
的创建移动到 之前 file/directory 检查,因为它对两个部分都是通用的。最后,如果您正在处理的目录实际上不存在,您将遇到麻烦,因为
opendir
将 return NULL,您将立即尝试将其传递给readdir
.
考虑到所有这些,我将从以下程序开始,该程序实际上 遍历 树并打印出它找到的所有文件。一旦你对此感到满意,你可以在删除的位中添加回来:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int rmrf(char *path) {
char *path_copy = malloc(1024);
DIR *directory = opendir(path);
if (directory != NULL) {
struct dirent *entry = readdir(directory);
while (entry != NULL) {
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) {
sprintf(path_copy, "%s/%s", path, entry->d_name);
if (entry->d_type == DT_DIR) {
rmrf(path_copy);
puts(path);
} else {
puts(path_copy);
}
}
entry = readdir(directory);
}
closedir(directory);
}
free(path_copy);
return 0;
}
主要代码只是一个驱动程序,用于确保正确设置思想。只要确保在 运行ning 之前,您没有(在当前目录中)要保留的 paxtest
或 paxtest2
文件或目录。
int main(void) {
system("rm -rf paxjunk");
system("mkdir paxjunk");
system("touch paxjunk/0.txt");
system("mkdir paxjunk/1");
system("touch paxjunk/1/1.txt");
system("mkdir paxjunk/2");
system("touch paxjunk/2/2.txt");
rmrf("paxjunk");
puts("===");
system("rm -rf paxjunk2");
rmrf("paxjunk2");
puts("===");
system("rm -rf paxjunk");
return 0;
}
当你运行这个时,你应该看到它工作正常:
paxjunk/0.txt
paxjunk/1/1.txt
paxjunk
paxjunk/2/2.txt
paxjunk
===
===