1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
| #include "apue.h"
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
typedef int Myfunc(const char *, const struct stat *, int);
static Myfunc myfunc_rename;
static int dopath(Myfunc *);
static int myftw(char *, Myfunc *);
static char *fullpath; // 存储文件完整路径
static char *target_filename; // 要查找并重命名的目标文件名
static int rename_count = 0; // 成功重命名的文件数
// 文件类型标记
#define FTW_F 1 /* 普通文件 */
#define FTW_D 2 /* 目录 */
#define FTW_DNR 3 /* 不可读目录 */
#define FTW_NS 4 /* 无法stat的文件 */
int main(int argc, char *argv[])
{
int ret;
// 校验参数:支持 myfind <指定目录> <要改名的文件名>
if (argc != 3) {
err_quit("usage: myfind <target_directory> <filename_to_rename>");
}
target_filename = argv[2];
rename_count = 0;
ret = myftw(argv[1], myfunc_rename);
if (rename_count == 0) {
printf("未找到名为 '%s' 的文件,无需重命名\n", target_filename);
} else {
printf("成功将 %d 个文件重命名为 'pass'\n", rename_count);
}
exit(ret);
}
static int myftw(char *pathname, Myfunc *func)
{
size_t len;
fullpath = path_alloc(&len); // 从apue库获取路径缓冲区
strncpy(fullpath, pathname, len);
fullpath[len-1] = 0; // 确保字符串终止
return(dopath(func));
}
static int dopath(Myfunc *func)
{
struct stat statbuf;
struct dirent *dirp;
DIR *dp;
int ret;
char *ptr;
// 获取文件属性失败
if (lstat(fullpath, &statbuf) < 0)
return(func(fullpath, &statbuf, FTW_NS));
// 如果是普通文件,执行重命名逻辑
if (S_ISDIR(statbuf.st_mode) == 0)
return(func(fullpath, &statbuf, FTW_F));
// 如果是目录,先执行回调(无实际操作)
if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
return(ret);
// 拼接子目录路径
ptr = fullpath + strlen(fullpath);
*ptr++ = '/';
*ptr = 0;
// 打开目录失败
if ((dp = opendir(fullpath)) == NULL)
return(func(fullpath, &statbuf, FTW_DNR));
// 遍历目录下的所有文件/子目录
while ((dirp = readdir(dp)) != NULL) {
// 跳过.和..
if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
continue;
// 拼接子文件路径
strcpy(ptr, dirp->d_name);
// 递归处理子文件/子目录
if ((ret = dopath(func)) != 0)
break;
}
// 恢复路径(移除最后拼接的子文件名)
ptr[-1] = 0;
// 关闭目录
if (closedir(dp) < 0)
err_ret("无法关闭目录: %s", fullpath);
return(ret);
}
// 查找目标文件并将其重命名为pass
static int myfunc_rename(const char *pathname, const struct stat *statptr, int type)
{
// 仅处理普通文件
if (type != FTW_F)
return 0;
// 提取文件名(路径最后一个/后的部分)
char *filename = strrchr(pathname, '/');
if (filename == NULL) {
filename = (char *)pathname; // 无/,直接是文件名
} else {
filename++; // 跳过/,指向实际文件名
}
// 匹配到目标文件,执行重命名
if (strcmp(filename, target_filename) == 0) {
// 拼接新路径:原目录 + /pass
char new_path[PATH_MAX];
strncpy(new_path, pathname, strrchr(pathname, '/') - pathname + 1);
strcat(new_path, "pass");
// 执行重命名
if (rename(pathname, new_path) == 0) {
printf("成功重命名: %s -> %s\n", pathname, new_path);
rename_count++;
} else {
err_ret("重命名失败: %s", pathname);
}
}
return 0;
}
|