Linux 使用C语言删除一个非空的目录

发布于:2024-04-14 ⋅ 阅读:(116) ⋅ 点赞:(0)

一、简介

Linux 下可以使用 rmdir 系统调用来删除一个目录,但是只能删除一个非空目录。

NAME
       rmdir - delete a directory

SYNOPSIS
       #include <unistd.h>

       int rmdir(const char *pathname);

DESCRIPTION
       rmdir() deletes a directory, which must be empty.

在 shell命令行我们用 rm -rf 来删除一个目录,那我们仿照 rm -rf 的原理来实现一个使用C语言删除一个非空的目录。

当执行 rm -rf 命令时,它会按照以下步骤进行操作:

首先,命令会尝试打开指定的目录 <directory>。
如果成功打开目录,命令会遍历目录中的所有子目录和文件。
对于每个子目录和文件,命令会递归调用自身,以便删除子目录和文件。
如果遇到子目录,将按照相同的步骤递归删除子目录及其内容。
如果遇到文件,命令将直接删除文件。
删除完成后,命令关闭目录。

(1)使用 tree 命令查看目录结构:

# tree dir_test/
dir_test/
├── 3.txt
├── 4.txt
├── 5.txt
└── dir1
    ├── 1.txt
    └── 2.txt

1 directory, 5 files

(2)使用 strace 来 追踪 rm -rf 命令:

[root@localhost c_test]# strace -e trace=file rm -rf dir_test/
execve("/usr/bin/rm", ["rm", "-rf", "dir_test/"], 0x7ffe2a252c50 /* 27 vars */) = 0
......
newfstatat(AT_FDCWD, "dir_test/", {st_mode=S_IFDIR|0755, st_size=57, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "dir_test/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
openat(AT_FDCWD, "dir_test/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
newfstatat(4, "dir1", {st_mode=S_IFDIR|0755, st_size=32, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(4, "dir1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
openat(4, "dir1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
unlinkat(5, "1.txt", 0)                 = 0
unlinkat(5, "2.txt", 0)                 = 0
unlinkat(4, "dir1", AT_REMOVEDIR)       = 0
unlinkat(4, "3.txt", 0)                 = 0
unlinkat(4, "4.txt", 0)                 = 0
unlinkat(4, "5.txt", 0)                 = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0

主要是:

unlinkat(5, "1.txt", 0)                 = 0
unlinkat(5, "2.txt", 0)                 = 0
unlinkat(4, "dir1", AT_REMOVEDIR)       = 0
unlinkat(4, "3.txt", 0)                 = 0
unlinkat(4, "4.txt", 0)                 = 0
unlinkat(4, "5.txt", 0)                 = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0

可以看到删除一个目录,首先将该目录下的文件删除掉,然后再删除掉该空目录。

二、代码演示

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <limits.h>

void removeDirectory(const char* dirPath) {
    struct stat st;
    if (lstat(dirPath, &st) == -1) {
        perror("lstat");
        return;
    }

    if (S_ISDIR(st.st_mode)) {
        DIR* dir = opendir(dirPath);
        if (dir == NULL) {
            perror("opendir");
            return;
        }

		char path[PATH_MAX];
        struct dirent* entry;
        while ((entry = readdir(dir)) != NULL) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }

            snprintf(path, sizeof(path), "%s/%s", dirPath, entry->d_name);
            removeDirectory(path);
        }

        closedir(dir);

        if (rmdir(dirPath) == -1) {
            perror("rmdir");
            return;
        }

        printf("Directory %s deleted successfully.\n", dirPath);
    } else if (S_ISREG(st.st_mode)) {
        if (remove(dirPath) == -1) {
            perror("remove");
            return;
        }
        printf("File %s deleted successfully.\n", dirPath);
    } else {
        printf("%s is of unknown file type.\n", dirPath);
    }
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        printf("Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    const char* filePath = argv[1];

    removeDirectory(filePath);

    return 0;
}
# ./a.out dir_test/
File dir_test//dir1/1.txt deleted successfully.
File dir_test//dir1/2.txt deleted successfully.
Directory dir_test//dir1 deleted successfully.
File dir_test//3.txt deleted successfully.
File dir_test//4.txt deleted successfully.
File dir_test//5.txt deleted successfully.
Directory dir_test/ deleted successfully.
unlinkat(5, "1.txt", 0)                 = 0
unlinkat(5, "2.txt", 0)                 = 0
unlinkat(4, "dir1", AT_REMOVEDIR)       = 0
unlinkat(4, "3.txt", 0)                 = 0
unlinkat(4, "4.txt", 0)                 = 0
unlinkat(4, "5.txt", 0)                 = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0

可以看到和 rm -rf 命令删除非空目录过程相同。


网站公告

今日签到

点亮在社区的每一天
去签到