Linux dd 命令详解:工作原理与实用指南(C/C++代码实现) ...

打印 上一主题 下一主题

主题 846|帖子 846|积分 2538

这段代码是一个模仿 Linux dd 命令的工具,它用于在不同文件之间复制数据。dd 是一个非常强盛的命令行工具,可以用于数据备份、转换和复制。下面我将详细解释这段代码的原理、实现方式以及如何运行和测试。
Linux dd 命令的工作原理

dd 命令是 Unix 和 Linux 系统中非常强盛的文件复制和转换工具。它通过指定块大小(block size)来读取和写入数据,实现高效的文件或设备复制。dd 命令不仅能够处理平凡文件,还能直接操纵设备文件,这使得它在系统备份、规复和数据克隆等使命中非常有用。

  • 基本语法:dd if=输入文件 of=输出文件 [选项]

    • if:指定输入文件名或设备名。
    • of:指定输出文件名或设备名。
    • [选项]:各种可选参数,用于控制复制活动。

  • 常用选项

    • bs:设置读写的块大小。例如:bs=4M。
    • count:复制的块数。例如:count=1。
    • conv:指定数据转换选项,如 conv=sync 确保同步模式。
    • status=progress:表现详细的进度信息。

  • 工作流程

    • 打开源和目标文件/设备:dd 命令会先尝试打开指定的输入和输出文件或设备。
    • 按块读取和写入:根据指定的块大小(bs),dd 从输入文件或设备读取数据,并写入到输出文件或设备中。
    • 数据处理:在读写过程中,dd 可以根据指定的转换选项对数据进行处理,如大小写转换、字节顺序转换等。
    • 重复操纵:上述过程会根据指定的块数(count)反复进行,直到完成全部数据的复制或转换。

命令利用用

dd 的基本命令行格式如下:
  1. dd if=<input_file> of=<output_file> [其他参数]
复制代码


  • if:指定输入文件。
  • of:指定输出文件。
以下是一些常用的参数示例:


  • bs:设置块大小,例如 bs=1024。
  • count:设置复制的块数,例如 count=10。
  • skip:设置跳过的块数,例如 skip=5。
  • seek:设置输出文件中跳过的块数,例如 seek=5。
示例

复制一个文件的前 10MB 到另一个文件:
  1. dd if=/dev/zero of=example.img bs=1M count=10
复制代码
将一个磁盘分区备份到另一个磁盘分区:
  1. dd if=/dev/sda of=/dev/sdb
复制代码
基本文件复制:
  1. dd if=inputfile of of=outputfile bs=64K count=1
复制代码
将 inputfile 复制到 outputfile,每次读取和写入 64KB 的数据块,只复制一个块。
备份和还原硬盘:
  1. dd if=/dev/sda of=/path/to/backup.img bs=4M
  2. dd if=/path/to/backup.img of=/dev/sdb bs=4M
复制代码
将整个硬盘 /dev/sda 备份到 backup.img 文件中,然后将 backup.img 还原到 /dev/sdb。
创建镜像文件:
  1. dd if=/dev/zero of=imagefile.img bs=1G count=10
复制代码
创建一个名为 imagefile.img 的 10GB 镜像文件,内容全为零。
制作启动盘:
  1. dd if=boot.img of=/dev/sdb bs=4M
复制代码
将 boot.img 写入到 USB 设备 /dev/sdb,制作可启动的 USB 盘。
擦除硬盘数据:
  1. dd if=/dev/urandom of of=/dev/sda bs=4M
复制代码
使用随机数据覆盖整个硬盘,确保数据无法规复。
日常定位分析

dd 命令在系统规复、数据规复和磁盘克隆等场景中非常有用。例如,当你需要从一个破坏的文件系统中规复数据时,可以使用 dd 来复制文件系统的一部分到另一个康健的磁盘上,然后对复制的数据进行分析和规复。
三、dd 命令在实际工作中的定位与分析

dd 命令因其强盛的功能和灵活性,在系统管理和运维工作中有着广泛的应用场景。以下是几个典型的应用场景及其分析:

  • 系统备份与规复

    • 场景:定期备份服务器上的硬盘或分区,以防数据丢失或系统故障。
    • 分析:通过 dd 命令,可以创建整个硬盘或分区的镜像文件,方便存储和快速规复。别的,还可以使用压缩工具(如 gzip)进一步减小镜像文件的大小。

  • 数据克隆和迁移

    • 场景:在更换硬盘或迁移数据时,需要将旧硬盘上的数据完整复制到新硬盘。
    • 分析:dd 命令可以直接操纵设备文件,无需颠末文件系统,从而提高数据复制的效率和可靠性。这对于大规模数据迁移尤其有用。

  • 制作启动盘和规复盘

    • 场景:需要制作可启动的 USB 盘或 CD/DVD,用于系统安装或故障排查。
    • 分析:dd 命令可以将 ISO 镜像文件直接写入到 USB 或光盘设备,操纵简单且高效。这在紧急情况下尤为重要,如系统崩溃后的规复工作。

  • 安全删除数据

    • 场景:需要彻底删除敏感数据,确保无法通过规复工具找回。
    • 分析:通过用随机数据覆盖硬盘,可以有用防止数据被规复。这种方法比单纯的文件删除更为安全,实用于处理包罗敏感信息的硬盘。

  • 性能测试

    • 场景:测试磁盘的读写速率,评估存储设备的性能。
    • 分析:dd 命令可以天生大规模的测试数据,并通过计时等方式测量磁盘的读写速率。这对于存储设备的选型和性能优化具有重要参考价值。

Linux dd 命令详解:工作原理与实用指南(C/C++代码实现)

  1. size_t free_mem()
  2. {
  3.         uint64_t n = 0;
  4.         char buf[1024], found = 0;
  5.         FILE *f = fopen("/proc/meminfo", "r");
  6.         if (!f)
  7.                 return 1024*1024;
  8.         memset(buf, 0, sizeof(buf));
  9.         for (;!feof(f);) {
  10.                 fgets(buf, sizeof(buf), f);
  11.                 if (strstr(buf, "MemFree:")) {
  12.                         found = 1;
  13.                         break;
  14.                 }
  15.         }
  16.         fclose(f);
  17.         if (!found)
  18.                 return 1024*1024;
  19.         n = strtoul(buf + 9, NULL, 10);
  20.         if (!n)
  21.                 return 1024*1024;
  22.         /* kB? */
  23.         if (strchr(buf + 9, 'k'))
  24.                 n <<= 10;
  25.         else if (strchr(buf + 9, 'M'))
  26.                 n <<= 20;
  27.         return n/2;
  28. }
  29. ...
  30. #ifdef ANDROID
  31. int copy_splice(struct dd_config *);
  32. int copy_splice_cores(struct dd_config *ddc)
  33. {
  34.         return copy_splice(ddc);
  35. }
  36. #else
  37. int copy_splice_cores(struct dd_config *ddc)
  38. {
  39.         int ifd, ofd, p[2] = {-1, -1};
  40.         ssize_t r = 0, cpu_size = 0;
  41.         size_t n = 0, min_bs = 4096;
  42.         cpu_set_t *cpu_set = NULL;
  43.         if (prepare_copy(ddc, &ifd, &ofd) < 0)
  44.                 return -1;
  45.         if ((cpu_set = CPU_ALLOC(2)) == NULL) {
  46.                 close(ifd); close(ofd);
  47.                 return -1;
  48.         }
  49.         cpu_size = CPU_ALLOC_SIZE(2);
  50.         CPU_ZERO_S(cpu_size, cpu_set);
  51.         if (pipe(p) < 0) {
  52.                 ddc->saved_errno = errno;
  53.                 close(ifd); close(ofd);
  54.                 close(p[0]); close(p[1]);
  55.                 return -1;
  56.         }
  57. #ifdef F_SETPIPE_SZ
  58.         for (n = 29; n >= 20; --n) {
  59.                 if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)
  60.                         break;
  61.         }
  62. #endif
  63.         n = ddc->bs;
  64.         if (fork() == 0) {
  65.                 /* bind to CPU#0 */
  66.                 CPU_SET_S(ddc->cores - 1, cpu_size, cpu_set);
  67.                 sched_setaffinity(0, cpu_size, cpu_set);
  68.                 close(p[0]);
  69.                 for (;ddc->b_in != ddc->count && !sigint;) {
  70.                         if (n > ddc->count - ddc->b_in)
  71.                                 n = ddc->count - ddc->b_in;
  72.                         r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE|SPLICE_F_NONBLOCK);
  73.                         if (r == 0)
  74.                                 break;
  75.                         if (r < 0) {
  76.                                 if (errno != EAGAIN)
  77.                                         break;
  78.                                 /* If running out of pipe buffer, decrease bs */
  79.                                 r = 0;
  80.                                 n = min_bs;
  81.                         }
  82.                         ddc->b_in += r;
  83.                 }
  84.                 exit(0);
  85.         }
  86.         /* bind to CPU#1 */
  87.         CPU_SET_S(ddc->cores - 2, cpu_size, cpu_set);
  88.         sched_setaffinity(0, cpu_size, cpu_set);
  89.         for (;ddc->b_out != ddc->count;) {
  90.                 r = splice(p[0], NULL, ofd, NULL, n, SPLICE_F_MORE);
  91.                 if (r <= 0) {
  92.                         ddc->saved_errno = errno;
  93.                         break;
  94.                 }
  95.                 ddc->b_out += r;
  96.                 ++ddc->rec_out;
  97.         }
  98.         ddc->rec_in = ddc->rec_out;
  99.         close(ifd);
  100.         close(ofd);
  101.         close(p[0]);
  102.         close(p[1]);
  103.         wait(NULL);
  104.         if (r < 0)
  105.                 return -1;
  106.         return 0;
  107. }
  108. #endif
  109. int copy_splice(struct dd_config *ddc)
  110. {
  111. ...
  112.         if (prepare_copy(ddc, &ifd, &ofd) < 0)
  113.                 return -1;
  114.         if (pipe(p) < 0) {
  115.                 ddc->saved_errno = errno;
  116.                 close(ifd); close(ofd);
  117.                 close(p[0]); close(p[1]);
  118.                 return -1;
  119.         }
  120. #ifdef F_SETPIPE_SZ
  121.         for (n = 29; n >= 20; --n) {
  122.                 if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)
  123.                         break;
  124.         }
  125. #endif
  126.         n = ddc->bs;
  127.         for (;ddc->b_out != ddc->count && !sigint;) {
  128.                 if (n > ddc->count - ddc->b_out)
  129.                         n = ddc->count - ddc->b_out;
  130.                 r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);
  131.                 if (r <= 0) {
  132.                         ddc->saved_errno = errno;
  133.                         break;
  134.                 }
  135.                 ++ddc->rec_in;
  136.                 r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);
  137.                 if (r <= 0) {
  138.                         ddc->saved_errno = errno;
  139.                         break;
  140.                 }
  141.                 ddc->b_out += r;
  142.                 ++ddc->rec_out;
  143.         }
  144.         close(ifd);
  145.         close(ofd);
  146.         close(p[0]);
  147.         close(p[1]);
  148.         if (r < 0)
  149.                 return -1;
  150.         return 0;
  151. }
  152. int copy_mmap(struct dd_config *ddc)
  153. {
  154. ...
  155.         if (prepare_copy(ddc, &ifd, &ofd) < 0)
  156.                 return -1;
  157.         if (ddc->fsize != (off_t)-1) {
  158.                 if (ftruncate(ofd, ddc->fsize) < 0) {
  159.                         ddc->saved_errno = errno;
  160.                         close(ifd);
  161.                         close(ofd);
  162.                         return -1;
  163.                 }
  164.         }
  165.         for (;ddc->b_out != ddc->count && !sigint;) {
  166.                 n = ddc->mmap;
  167.                 bs = ddc->bs;
  168.                 if (n > ddc->count - ddc->b_out)
  169.                         n = ddc->count - ddc->b_out;
  170.                 if (bs > n)
  171.                         bs = n;
  172.                 if (ddc->fsize == (off_t)-1) {
  173.                         if (ftruncate(ofd, ddc->b_out + n) < 0) {
  174.                                 ddc->saved_errno = errno;
  175.                                 break;
  176.                         }
  177.                 }
  178.                 addr = mmap(NULL, n, PROT_WRITE, MAP_SHARED, ofd, ddc->b_out + ddc->skip);
  179.                 if (addr == MAP_FAILED) {
  180.                         ddc->saved_errno = errno;
  181.                         break;
  182.                 }
  183.                 for (i = 0; i < n; i += r) {
  184.                         if (i + bs > n)
  185.                                 bs = n - i;
  186.                         r = read(ifd, addr + i, bs);
  187.                         if (r <= 0) {
  188.                                 ddc->saved_errno = errno;
  189.                                 munmap(addr, n);
  190.                                 break;
  191.                         }
  192.                         ddc->b_out += r;
  193.                         ++ddc->rec_in;
  194.                 }
  195. ...
  196.         }
  197.         if (ddc->fsize != ddc->b_out)
  198.                 ftruncate(ofd, ddc->b_out);
  199.         close(ifd);
  200.         close(ofd);
  201.         if (r < 0 || addr == MAP_FAILED)
  202.                 return -1;
  203.         return 0;
  204. }
  205. int copy_sendfile(struct dd_config *ddc)
  206. {
  207. ...
  208.         off = ddc->skip;
  209.         n = ddc->bs;
  210.         for (;ddc->b_out < ddc->count && !sigint;) {
  211.                 if (n > ddc->count - ddc->b_out)
  212.                         n = ddc->count - ddc->b_out;
  213.                 r = sendfile(ofd, ifd, &off, n);
  214.                 if (r < 0) {
  215.                         ddc->saved_errno = errno;
  216.                         ret = -1;
  217.                         break;
  218.                 }
  219.                 ++ddc->rec_in; ++ddc->rec_out;
  220.                 ddc->b_in += r;
  221.                 ddc->b_out += r;
  222.         }
  223.         close(ifd);
  224.         close(ofd);
  225.         return ret;
  226. }
  227. int copy(struct dd_config *ddc)
  228. {
  229. ...
  230.         if (ddc->cores)
  231.                 r = copy_splice_cores(ddc);
  232.         else if (ddc->mmap)
  233.                 r = copy_mmap(ddc);
  234.         else if (ddc->sf)
  235.                 r = copy_sendfile(ddc);
  236.         else
  237.                 r = copy_splice(ddc);
  238.         ddc->t_end = time(NULL);
  239.         /* 避免div为零 */
  240.         if (ddc->t_start == ddc->t_end)
  241.                 ++ddc->t_end;
  242.         return r;
  243. }
  244. void print_stat(const struct dd_config *ddc)
  245. {
  246. ...
  247. #ifdef ANDROID
  248.         fprintf(stderr, "%llu records in\n%llu records out\n%llu bytes (%llu MB) copied, %lu s, %f MB/s [%f mB/s]\n",
  249.                 ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),
  250.                 ddc->t_end - ddc->t_start,
  251.                 ((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),
  252.                 ((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
  253. #else
  254.         fprintf(stderr, "%lu records in\n%lu records out\n%lu bytes (%lu MB) copied, %lu s, %f MB/s [%f mB/s]\n",
  255.                 ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),
  256.                 ddc->t_end - ddc->t_start,
  257.                 ((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),
  258.                 ((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
  259. #endif
  260. }
  261. void sig_int(int x)
  262. {
  263.         fprintf(stderr, "SIGINT! Aborting ...\n");
  264.         sigint = 1;
  265.         return;
  266. }
  267. int main(int argc, char **argv)
  268. {
  269. ...
  270.         config.bs = 1<<16;
  271.         config.in = "/dev/stdin";
  272.         config.out = "/dev/stdout";
  273.         /* 模拟“dd”参数解析 */
  274.         for (i = 1; i < argc; ++i) {
  275.                 if (strcmp(argv[i], "-h") == 0 ||
  276.                     strcmp(argv[i], "--help") == 0)
  277.                         usage(argv[0]);
  278.                 memset(buf, 0, sizeof(buf));
  279.                 if (sscanf(argv[i], "if=%1023c", buf) == 1)
  280.                         config.in = strdup(buf);
  281.                 else if (sscanf(argv[i], "of=%1023c", buf) == 1)
  282.                         config.out = strdup(buf);
  283.                 else if (sscanf(argv[i], "skip=%1023c", buf) == 1)
  284.                         config.skip = strtoul(buf, NULL, 10);
  285.                 else if (sscanf(argv[i], "seek=%1023c", buf) == 1)
  286.                         config.seek = strtoul(buf, NULL, 10);
  287.                 else if (sscanf(argv[i], "count=%1023c", buf) == 1)
  288.                         config.count = strtoul(buf, NULL, 10);
  289.                 else if (sscanf(argv[i], "mmap=%1023c", buf) == 1) {
  290.                         if (!config.cores) {
  291.                                 /* Size in MB */
  292.                                 config.mmap = strtoul(buf, NULL, 10);
  293.                                 config.mmap <<= 20;
  294.                         }
  295.                 } else if (sscanf(argv[i], "cores=%1023c", buf) == 1) {
  296.                         config.cores = strtoul(buf, NULL, 10);
  297.                         if (config.cores < 2)
  298.                                 config.cores = 2;
  299.                         config.mmap = 0;
  300.                 } else if (strcmp(argv[i], "send") == 0) {
  301.                         config.sf = 1;
  302.                 } else if (strcmp(argv[i], "direct") == 0) {
  303.                         config.direct = 1;
  304.                 } else if (sscanf(argv[i], "bs=%1023c", buf) == 1) {
  305.                         config.bs = strtoul(buf, NULL, 10);
  306.                 } else if (strcmp(argv[i], "bs") == 0) {
  307.                         config.bs = 0;
  308.                 } else if (strcmp(argv[i], "quiet") == 0) {
  309.                         config.quiet = 1;
  310.                 } else if (strcmp(argv[i], "nosync") == 0) {
  311.                         config.nosync = 1;
  312.                 }
  313.         }
  314. ...
  315.         return 0;
  316. }
复制代码
If you need the complete source code, please add the WeChat number (c17865354792)
编译完成后,你可以使用以下命令行参数来测试它:
   ./linux_dd if=<input_file> of=<output_file> [其他参数]

  例如,你可以使用以下命令来复制一个文件:
   ./linux_dd if=/dev/stdin of=/dev/stdout bs=1024 count=1024
  这个命令会从尺度输入读取数据,并将数据写入到尺度输出,每次复制 1024 字节,总共复制 1024 次。
代码中提供了多种复制计谋:

  • splice(2):使用 Linux 的 splice 系统调用来在管道和文件之间传输数据,这种方式可以有用地利用内核缓冲区,减少数据复制过程中的上下文切换。
  • mmap(2):通过内存映射的方式直接在内存中操纵文件数据,这种方式实用于大块数据的复制。
  • sendfile(2):在内核层面直接将数据从一个文件描述符传输到另一个,减少了数据在用户空间的拷贝。
  • 多核处理:代码还支持将数据复制使命分配到多个 CPU 焦点上,以提高复制效率。
增补内容


  • 安全性:在使用 dd 时,肯定要小心指定正确的输入和输出文件,错误的命令大概会导致数据丢失。
  • 效率:选择合适的块大小可以显著影响 dd 的性能。通常,较大的块大小可以提高复制速率。
  • 错误处理:dd 命令在实行过程中大概会遇到错误,了解如何解读错误信息对于办理问题至关重要。
  • 日志记载:dd 命令实行时可以重定向输出到日志文件,以便于过后分析。
  • 进度监控:可以通过 status=progress 参数来监控 dd 命令的实行进度。
结语

dd 命令是一个功能强盛的工具,它在 Linux 系统中扮演偏重要的角色。了解其工作原理和使用方法,可以资助你更有用地管理和操纵数据。在使用时,务必谨慎,以克制不必要的数据丧失。
Welcome to follow WeChat official account【程序猿编码

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

北冰洋以北

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表