测试用例
This commit is contained in:
+210
-1
@@ -3,14 +3,19 @@
|
||||
#include <windows.h>
|
||||
#include <io.h> // 提供 _get_osfhandle
|
||||
#include <direct.h>
|
||||
#include <dirent.h>
|
||||
#define C_ACCESS(path) _access(path, 0)
|
||||
#define C_MAKE_DIR(path) _mkdir(path) // Windows 下创建目录
|
||||
#define sys_rmdir(path) _rmdir(path)
|
||||
#define PATH_SEP '\\'
|
||||
#else
|
||||
#include <unistd.h> // 提供 fsync
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#define C_ACCESS(path) access(path, F_OK)
|
||||
#define C_MAKE_DIR(path) mkdir(path, 0755)
|
||||
#define sys_rmdir(path) rmdir(path)
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
@@ -276,4 +281,208 @@ c_err_t c_File_MkDirs(const char* path) {
|
||||
}
|
||||
|
||||
return C_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
c_err_t c_File_Rmdir(const char* path) {
|
||||
if (!path || path[0] == '\0') {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
// 调用操作系统底层移除目录的 API
|
||||
int result = sys_rmdir(path);
|
||||
|
||||
if (result == 0) {
|
||||
return C_ERR_OK; // 删除成功
|
||||
} else {
|
||||
// 删除失败(可能是由于目录不存在、无权限、或者目录非空)
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
c_err_t c_File_Rmdirs(const char* path) {
|
||||
if (!path || path[0] == '\0') {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
c_err_t status = C_ERR_OK;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// ==========================================
|
||||
// Windows 平台的递归删除实现
|
||||
// ==========================================
|
||||
char search_path[MAX_PATH];
|
||||
// Windows 检索目录需要追加 "\\*"
|
||||
snprintf(search_path, sizeof(search_path), "%s\\*", path);
|
||||
|
||||
WIN32_FIND_DATAA find_data;
|
||||
HANDLE h_find = FindFirstFileA(search_path, &find_data);
|
||||
|
||||
if (h_find == INVALID_HANDLE_VALUE) {
|
||||
// 如果目录根本不存在,或者无法打开,尝试直接当做文件 remove 移除(处理符号链接等边界)
|
||||
return remove(path) == 0 ? C_ERR_OK : C_ERR_FAIL;
|
||||
}
|
||||
|
||||
do {
|
||||
// 排除 Windows 的特殊目录 "." 和 ".."
|
||||
if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 拼接子项的完整路径
|
||||
char sub_path[MAX_PATH];
|
||||
snprintf(sub_path, sizeof(sub_path), "%s\\%s", path, find_data.cFileName);
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// 如果子项是目录,递归调用
|
||||
status = c_File_Rmdirs(sub_path);
|
||||
} else {
|
||||
// 如果子项是普通文件,取消只读属性(防止因只读导致删除失败),然后将其删除
|
||||
SetFileAttributesA(sub_path, FILE_ATTRIBUTE_NORMAL);
|
||||
status = (DeleteFileA(sub_path) != 0) ? C_ERR_OK : C_ERR_FAIL;
|
||||
}
|
||||
|
||||
if (status != C_ERR_OK) {
|
||||
break;
|
||||
}
|
||||
} while (FindNextFileA(h_find, &find_data));
|
||||
|
||||
FindClose(h_find);
|
||||
|
||||
#else
|
||||
// ==========================================
|
||||
// Linux / macOS (POSIX) 平台的递归删除实现
|
||||
// ==========================================
|
||||
DIR* dir = opendir(path);
|
||||
if (!dir) {
|
||||
// 无法打开作为目录处理,尝试按普通文件物理删除
|
||||
return remove(path) == 0 ? C_ERR_OK : C_ERR_FAIL;
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// 排除 Linux 的特殊目录 "." 和 ".."
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 拼接子项的完整路径
|
||||
char sub_path[1024];
|
||||
snprintf(sub_path, sizeof(sub_path), "%s/%s", path, entry->d_name);
|
||||
|
||||
struct stat statbuf;
|
||||
if (stat(sub_path, &statbuf) == 0) {
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
// 如果子项是目录,递归调用
|
||||
status = c_File_Rmdirs(sub_path);
|
||||
} else {
|
||||
// 如果子项是文件,执行普通删除
|
||||
status = (remove(sub_path) == 0) ? C_ERR_OK : C_ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != C_ERR_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
#endif
|
||||
|
||||
// ==========================================
|
||||
// 公共收尾:清空了内部所有子项后,最后删除外层空壳目录
|
||||
// ==========================================
|
||||
if (status == C_ERR_OK) {
|
||||
if (sys_rmdir(path) != 0) {
|
||||
status = C_ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
c_err_t c_File_Delete(const char* fileName) {
|
||||
if (!fileName || fileName[0] == '\0') {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
// 标准 C 库的 remove 能够直接删除文件(在某些平台上也能删除空目录)
|
||||
int result = remove(fileName);
|
||||
|
||||
if (result == 0) {
|
||||
return C_ERR_OK; // 删除成功
|
||||
} else {
|
||||
// 删除失败(文件不存在、或无权限、或文件正被某些操作系统强锁占用)
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
#define COPY_BUFFER_SIZE 4096
|
||||
|
||||
c_err_t c_File_Copy(const char* srcPath, const char* destPath) {
|
||||
if (!srcPath || srcPath[0] == '\0' || !destPath || destPath[0] == '\0') {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
FILE* src = fopen(srcPath, "rb");
|
||||
if (!src) return C_ERR_NOTFOUND;
|
||||
|
||||
FILE* dest = fopen(destPath, "wb");
|
||||
if (!dest) {
|
||||
fclose(src);
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
|
||||
char* buffer = (char*)malloc(COPY_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
fclose(src);
|
||||
fclose(dest);
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
|
||||
c_err_t status = C_ERR_OK;
|
||||
size_t bytes_read;
|
||||
|
||||
// 循环读写块,避免一次性读入大文件撑爆堆内存
|
||||
while ((bytes_read = fread(buffer, 1, COPY_BUFFER_SIZE, src)) > 0) {
|
||||
size_t bytes_written = fwrite(buffer, 1, bytes_read, dest);
|
||||
if (bytes_written < bytes_read) {
|
||||
status = C_ERR_FAIL; // 磁盘空间不足或写入错误
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
fclose(src);
|
||||
fclose(dest);
|
||||
|
||||
// 如果中途失败,清理掉生成的不完整目标文件
|
||||
if (status != C_ERR_OK) {
|
||||
remove(destPath);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
c_err_t c_File_Move(const char* oldPath, const char* newPath) {
|
||||
if (!oldPath || oldPath[0] == '\0' || !newPath || newPath[0] == '\0') {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
// 1. 尝试使用操作系统原生的轻量级重命名/移动
|
||||
if (rename(oldPath, newPath) == 0) {
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
// 2. 跨分区保底策略:如果因为跨文件系统挂载点导致 rename 失败,则执行 复制 + 删除
|
||||
c_err_t copy_err = c_File_Copy(oldPath, newPath);
|
||||
if (copy_err == C_ERR_OK) {
|
||||
if (remove(oldPath) == 0) {
|
||||
return C_ERR_OK;
|
||||
} else {
|
||||
// 如果删原文件失败,为了数据安全,把新拷过去的文件也撤销,避免数据状态不一致
|
||||
remove(newPath);
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return C_ERR_FAIL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user