好长时间没有更新了,偶然看到几年前写的一个复制工具,代码惨不忍睹,所以重写了一遍.
目的: xcp - 代替 Linux 的 cp 命令,复制大量文件时显示进度
实现: 遍历源文件两次,第一次统计,第二次复制
本次更新内容: 用统一的编码风格整理代码,减少递归函数使用的栈空间,调整参数处理方式使之同 cp 的习惯用法保持一致
附1: xcp.c
// #define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <stdarg.h>
#include <errno.h>
#include <assert.h>
/*
* 复制文件可以显示进度
*
* 两个思路:遍历文件一次,把文件名记录在一个列表,后续操作直接从列表中得到文件名
* 或者遍历两遍,第一次统计,第二次执行
*
* 关于进度条
* 1. 用定时器每隔1秒刷新一次要注意函数重入的问题
* 2. 两个线程工作线程统计/拷贝主线程刷新状态,似乎小题大做了
* 3. 一个线程有变化时刷新,这样就无法现实动画
*
* 2013-10-22
* 1. 添加命令行选项的处理。
* 2. 添加文件无法访问/目录无法创建或者文件/目录已经存在的情况的处理。
* 3. 如果没有任何文件成功复制时的提示信息BUG(在有文件detected的情况下)。
* 4. 复制文件,目标是已经存在的目录名时自动添加文件名而不是直接复制。
* 5. 结束时用human_time 来显示用去的时间。
*
* 2013-10-23
* 1. 统计阶段也要显示动画
*
* 2013-10-24
* 1. overwrite 提示后等待用户输入和定时器冲突的问题
*
* 2013-10-29
1. 多源拷贝在主函数做个循环,都要补齐文件名,判断是否存在等.
*
* 2020-1-10
* v0.2 重写整个程序
* 1. 使之符合 cp 命令的习惯
* 2. 遵循 linux 编码风格
*
* 2020-1-11
* v0.3 添加覆盖时 yes/no to all 选项
* v0.3.1 细节修订
* v0.3.2 细节修订
* v0.3.3 代码格式修订
*/
#define MAX_FMTSTR_LENGTH 2048/*传递给print_message函数的格式字符串最大长度*/
#define COPY_BUF_SIZE 4096 /*复制文件时每次读取的长度*/
#define MAX_PATH_LENGTH (PATH_MAX + 1)/*路径的最大长度*/
#define GBYTES (1024 * 1024 * 1024)
#define MBYTES (1024 * 1024)
#define KBYTES 1024
#define HOUR (60 * 60)
#define MINUTE 60
#define OP_CONTINUE 0
#define OP_SKIP 1
#define OP_CANCEL 2 /*walk 函数终止遍历退出*/
#define MSGT_PROMPT 0
#define MSGT_WARNING 1
#define MSGT_ERROR 2
#define MSGT_VERBOSE 3
/*启用大文件支持*/
//#define _LARGEFILE64_SOURCE
//#define _FILE_OFFSET_BITS 64
//#ifdef _LARGEFILE64_SOURCE
//#define stat stat64
//#define fopen fopen64
//#define fread fread64
//#define fwrite fwrite64
//#endif
typedef int (*op_func_t)(const char*, const char*, const struct stat*, const struct stat*);
typedef void (*sig_handler_t)(int);
/* 全局变量 */
int g_sum_file = 0;
int g_sum_dir = 0;
long long g_sum_size = 0;
int g_copied_file = 0;
int g_copied_dir = 0;
long long g_copied_size = 0;
time_t g_copy_start_time = 0;
int g_status_pause = 0;
int g_opt_d = 0;
int g_opt_f = 0;
int g_opt_q = 0;
int g_opt_r = 0;
int g_opt_v = 0;
char g_copy_buf[COPY_BUF_SIZE];
int g_auto_choice = 0;
/*显示为可读数字*/
static char *human_size(long long s, char *hs)
{
if (s >= GBYTES) {
sprintf(hs, "%.2fGB", (s * 1.0) / GBYTES);
} else if (s >= 1024 * 1024) {
sprintf(hs, "%.2fMB", (s * 1.0) / MBYTES);
} else if (s > 1024) {
sprintf(hs, "%.2fKB", (s * 1.0) / KBYTES);
} else {
sprintf(hs, "%lldB", s);
}
return hs;
}
/* human readable time */
static char *human_time(time_t t, char *text)
{
int h, m, s;
h = (int)(t / HOUR);
m = (int)((t % HOUR) / MINUTE);
s = (int)(t % HOU