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

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

Linux dd 命令的工作原理

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

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

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

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

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

命令行使用

dd 的基本命令行格式如下:

dd if=<input_file> of=<output_file> [其他参数]
  • if:指定输入文件。
  • of:指定输出文件。

以下是一些常用的参数示例:

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

示例

复制一个文件的前 10MB 到另一个文件:

dd if=/dev/zero of=example.img bs=1M count=10

将一个磁盘分区备份到另一个磁盘分区:

dd if=/dev/sda of=/dev/sdb

基本文件复制:

dd if=inputfile of of=outputfile bs=64K count=1

将 inputfile 复制到 outputfile,每次读取和写入 64KB 的数据块,只复制一个块。

备份和还原硬盘:

dd if=/dev/sda of=/path/to/backup.img bs=4M 
dd if=/path/to/backup.img of=/dev/sdb bs=4M 

将整个硬盘 /dev/sda 备份到 backup.img 文件中,然后将 backup.img 还原到 /dev/sdb。

创建镜像文件:

dd if=/dev/zero of=imagefile.img bs=1G count=10

创建一个名为 imagefile.img 的 10GB 镜像文件,内容全为零。

制作启动盘:

dd if=boot.img of=/dev/sdb bs=4M 

将 boot.img 写入到 USB 设备 /dev/sdb,制作可启动的 USB 盘。

擦除硬盘数据:

dd if=/dev/urandom of of=/dev/sda bs=4M 

使用随机数据覆盖整个硬盘,确保数据无法恢复。

日常定位分析

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

三、dd 命令在实际工作中的定位与分析

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

  1. 系统备份与恢复

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

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

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

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

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

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

size_t free_mem()
{uint64_t n = 0;char buf[1024], found = 0;FILE *f = fopen("/proc/meminfo", "r");if (!f)return 1024*1024;memset(buf, 0, sizeof(buf));for (;!feof(f);) {fgets(buf, sizeof(buf), f);if (strstr(buf, "MemFree:")) {found = 1;break;}}fclose(f);if (!found)return 1024*1024;n = strtoul(buf + 9, NULL, 10);if (!n)return 1024*1024;/* kB? */if (strchr(buf + 9, 'k'))n <<= 10;else if (strchr(buf + 9, 'M'))n <<= 20;return n/2;
}...#ifdef ANDROIDint copy_splice(struct dd_config *);int copy_splice_cores(struct dd_config *ddc)
{return copy_splice(ddc);
}#else
int copy_splice_cores(struct dd_config *ddc)
{int ifd, ofd, p[2] = {-1, -1};ssize_t r = 0, cpu_size = 0;size_t n = 0, min_bs = 4096;cpu_set_t *cpu_set = NULL;if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if ((cpu_set = CPU_ALLOC(2)) == NULL) {close(ifd); close(ofd);return -1;}cpu_size = CPU_ALLOC_SIZE(2);CPU_ZERO_S(cpu_size, cpu_set);if (pipe(p) < 0) {ddc->saved_errno = errno;close(ifd); close(ofd);close(p[0]); close(p[1]);return -1;}#ifdef F_SETPIPE_SZfor (n = 29; n >= 20; --n) {if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)break;}
#endifn = ddc->bs;if (fork() == 0) {/* bind to CPU#0 */CPU_SET_S(ddc->cores - 1, cpu_size, cpu_set);sched_setaffinity(0, cpu_size, cpu_set);close(p[0]);for (;ddc->b_in != ddc->count && !sigint;) {if (n > ddc->count - ddc->b_in)n = ddc->count - ddc->b_in;r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE|SPLICE_F_NONBLOCK);if (r == 0)break;if (r < 0) {if (errno != EAGAIN)break;/* If running out of pipe buffer, decrease bs */r = 0;n = min_bs;}ddc->b_in += r;}exit(0);}/* bind to CPU#1 */CPU_SET_S(ddc->cores - 2, cpu_size, cpu_set);sched_setaffinity(0, cpu_size, cpu_set);for (;ddc->b_out != ddc->count;) {r = splice(p[0], NULL, ofd, NULL, n, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}ddc->b_out += r;++ddc->rec_out;}ddc->rec_in = ddc->rec_out;close(ifd);close(ofd);close(p[0]);close(p[1]);wait(NULL);if (r < 0)return -1;return 0;
}
#endifint copy_splice(struct dd_config *ddc)
{
...if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if (pipe(p) < 0) {ddc->saved_errno = errno;close(ifd); close(ofd);close(p[0]); close(p[1]);return -1;}#ifdef F_SETPIPE_SZfor (n = 29; n >= 20; --n) {if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)break;}
#endifn = ddc->bs;for (;ddc->b_out != ddc->count && !sigint;) {if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}++ddc->rec_in;r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}ddc->b_out += r;++ddc->rec_out;}close(ifd);close(ofd);close(p[0]);close(p[1]);if (r < 0)return -1;return 0;
}int copy_mmap(struct dd_config *ddc)
{
...if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if (ddc->fsize != (off_t)-1) {if (ftruncate(ofd, ddc->fsize) < 0) {ddc->saved_errno = errno;close(ifd);close(ofd);return -1;}}for (;ddc->b_out != ddc->count && !sigint;) {n = ddc->mmap;bs = ddc->bs;if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;if (bs > n)bs = n;if (ddc->fsize == (off_t)-1) {if (ftruncate(ofd, ddc->b_out + n) < 0) {ddc->saved_errno = errno;break;}}addr = mmap(NULL, n, PROT_WRITE, MAP_SHARED, ofd, ddc->b_out + ddc->skip);if (addr == MAP_FAILED) {ddc->saved_errno = errno;break;}for (i = 0; i < n; i += r) {if (i + bs > n)bs = n - i;r = read(ifd, addr + i, bs);if (r <= 0) {ddc->saved_errno = errno;munmap(addr, n);break;}ddc->b_out += r;++ddc->rec_in;}...}if (ddc->fsize != ddc->b_out)ftruncate(ofd, ddc->b_out);close(ifd);close(ofd);if (r < 0 || addr == MAP_FAILED)return -1;return 0;
}int copy_sendfile(struct dd_config *ddc)
{
...off = ddc->skip;n = ddc->bs;for (;ddc->b_out < ddc->count && !sigint;) {if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;r = sendfile(ofd, ifd, &off, n);if (r < 0) {ddc->saved_errno = errno;ret = -1;break;}++ddc->rec_in; ++ddc->rec_out;ddc->b_in += r;ddc->b_out += r;}close(ifd);close(ofd);return ret;
}int copy(struct dd_config *ddc)
{
...if (ddc->cores)r = copy_splice_cores(ddc);else if (ddc->mmap)r = copy_mmap(ddc);else if (ddc->sf)r = copy_sendfile(ddc);elser = copy_splice(ddc);ddc->t_end = time(NULL);/* 避免div为零 */if (ddc->t_start == ddc->t_end)++ddc->t_end;return r;
}void print_stat(const struct dd_config *ddc)
{
...#ifdef ANDROIDfprintf(stderr, "%llu records in\n%llu records out\n%llu bytes (%llu MB) copied, %lu s, %f MB/s [%f mB/s]\n",ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),ddc->t_end - ddc->t_start,((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
#elsefprintf(stderr, "%lu records in\n%lu records out\n%lu bytes (%lu MB) copied, %lu s, %f MB/s [%f mB/s]\n",ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),ddc->t_end - ddc->t_start,((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
#endif}void sig_int(int x)
{fprintf(stderr, "SIGINT! Aborting ...\n");sigint = 1;return;
}int main(int argc, char **argv)
{
...config.bs = 1<<16;config.in = "/dev/stdin";config.out = "/dev/stdout";/* 模拟“dd”参数解析 */for (i = 1; i < argc; ++i) {if (strcmp(argv[i], "-h") == 0 ||strcmp(argv[i], "--help") == 0)usage(argv[0]);memset(buf, 0, sizeof(buf));if (sscanf(argv[i], "if=%1023c", buf) == 1)config.in = strdup(buf);else if (sscanf(argv[i], "of=%1023c", buf) == 1)config.out = strdup(buf);else if (sscanf(argv[i], "skip=%1023c", buf) == 1)config.skip = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "seek=%1023c", buf) == 1)config.seek = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "count=%1023c", buf) == 1)config.count = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "mmap=%1023c", buf) == 1) {if (!config.cores) {/* Size in MB */config.mmap = strtoul(buf, NULL, 10);config.mmap <<= 20;}} else if (sscanf(argv[i], "cores=%1023c", buf) == 1) {config.cores = strtoul(buf, NULL, 10);if (config.cores < 2)config.cores = 2;config.mmap = 0;} else if (strcmp(argv[i], "send") == 0) {config.sf = 1;} else if (strcmp(argv[i], "direct") == 0) {config.direct = 1;} else if (sscanf(argv[i], "bs=%1023c", buf) == 1) {config.bs = strtoul(buf, NULL, 10);} else if (strcmp(argv[i], "bs") == 0) {config.bs = 0;} else if (strcmp(argv[i], "quiet") == 0) {config.quiet = 1;} else if (strcmp(argv[i], "nosync") == 0) {config.nosync = 1;}}...return 0;
}

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 次。

代码中提供了多种复制策略:

  1. splice(2):使用 Linux 的 splice 系统调用来在管道和文件之间传输数据,这种方式可以有效地利用内核缓冲区,减少数据复制过程中的上下文切换。

  2. mmap(2):通过内存映射的方式直接在内存中操作文件数据,这种方式适用于大块数据的复制。

  3. sendfile(2):在内核层面直接将数据从一个文件描述符传输到另一个,减少了数据在用户空间的拷贝。

  4. 多核处理:代码还支持将数据复制任务分配到多个 CPU 核心上,以提高复制效率。

补充内容

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

结语

dd 命令是一个功能强大的工具,它在 Linux 系统中扮演着重要的角色。了解其工作原理和使用方法,可以帮助你更有效地管理和操作数据。在使用时,务必谨慎,以避免不必要的数据损失。

Welcome to follow WeChat official account【程序猿编码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/64510.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT客户端安装教程(附下载链接)

用惯了各类AI的我们发现每天打开网页还挺不习惯和麻烦&#xff0c;突然发现客户端上架了&#xff0c;懂摸鱼的人都知道这里面的道行有多深&#xff0c;话不多说&#xff0c;开整&#xff01; 以下是ChatGPT客户端的详细安装教程&#xff0c;适用于Windows和Mac系统&#xff1a…

《C 语言携手 PaddlePaddle C++ API:开启深度学习开发新征程》

在深度学习领域&#xff0c;PaddlePaddle 作为一款强大的深度学习框架&#xff0c;为开发者提供了丰富的功能和高效的计算能力。而 C 语言&#xff0c;凭借其高效性和广泛的应用场景&#xff0c;与 PaddlePaddle 的 C API 相结合&#xff0c;能够为深度学习开发带来独特的优势。…

ARM CCA机密计算安全模型之固件启动

安全之安全(security)博客目录导读 目录 1、安全启动(Verified boot) 2、镜像格式和签名方案 3、防回滚 4、离线启动(Off-line boot) 5、CCA HES固件启动流程 6、CCA系统安全域启动过程 7、应用程序PE启动过程 8、稳健性 本节定义了将CCA固件引导至可证明状态的要…

Element@2.15.14-tree checkStrictly 状态实现父项联动子项,实现节点自定义编辑、新增、删除功能

背景&#xff1a;现在有一个新需求&#xff0c;需要借助树结构来实现词库的分类管理&#xff0c;树的节点是不同的分类&#xff0c;不同的分类可以有自己的词库&#xff0c;所以父子节点是互不影响的&#xff1b;同样为了选择的方便性&#xff0c;提出了新需求&#xff0c;选择…

【ALSA】snd_pcm_avail 接口

目录 简介使用场景注意事项函数签名代码示例 简介 snd_pcm_avail 是 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;库中的一个函数&#xff0c;用于获取 PCM&#xff08;Pulse Code Modulation&#xff09;设备环形缓冲区中可用的音频数据量。这个函数对于音…

计算机网络——期末复习(1)背诵

背诵 交换机与路由器&#xff1a;交换机连接同一子网&#xff0c;利用帧中的目的物理地址转发帧&#xff0c;工作在数据链路层&#xff1b;路由器连接不同子网&#xff0c;利用IP数据报中的目的IP地址转发IP数据报&#xff0c;工作在网络层。五层的任务&#xff1a;&#xff0…

概率论得学习和整理27:关于离散的数组 随机变量数组的均值,方差的求法3种公式,思考和细节。

目录 1 例子1&#xff1a;最典型的&#xff0c;最简单的数组的均值&#xff0c;方差的求法 2 例子1的问题&#xff1a;例子1只是1个特例&#xff0c;而不是普遍情况。 2.1 例子1各种默认假设&#xff0c;导致了求均值和方差的特殊性&#xff0c;特别简单。 2.2 我觉得 加权…

【HarmonyOS NEXT】Web 组件的基础用法以及 H5 侧与原生侧的双向数据通讯

关键词&#xff1a;鸿蒙、ArkTs、Web组件、通讯、数据 官方文档Web组件用法介绍&#xff1a;文档中心 Web 组件加载沙箱中页面可参考我的另一篇文章&#xff1a;【HarmonyOS NEXT】 如何将rawfile中文件复制到沙箱中_鸿蒙rawfile 复制到沙箱-CSDN博客 目录 如何在鸿蒙应用中加…

ASP.NET Core - 依赖注入 自动批量注入

依赖注入配置变形 随着业务的增长&#xff0c;我们项目工作中的类型、服务越来越多&#xff0c;而每一个服务的依赖注入关系都需要在入口文件通过Service.Add{}方法去进行注册&#xff0c;这将是非常麻烦的&#xff0c;入口文件需要频繁改动&#xff0c;而且代码组织管理也会变…

Spring Boot 3.X:Unable to connect to Redis错误记录

一.背景 最近在搭建一个新项目&#xff0c;本着有新用新的原则&#xff0c;项目选择到了jdk17SpringBoot3.4。但是在测试Redis连接的时候却遇到了以下问题&#xff1a; redis连不上了。于是我先去检查了配置文件的连接信息&#xff0c;发现没问题&#xff1b;再去检查配置类&am…

FFmpeg第一话:FFmpeg 简介与环境搭建

FFmpeg 探索之旅 一、FFmpeg 简介与环境搭建 二、FFmpeg 解码详解 第一话&#xff1a;FFmpeg 简介与环境搭建 FFmpeg 探索之旅一、前言二、FFmpeg 是什么&#xff1f;三、简单介绍其历史背景四、为什么用 C学习 FFmpeg&#xff1f;&#xff08;一&#xff09;高性能优势&#…

(vue)el-table在表头添加筛选功能

(vue)el-table在表头添加筛选功能 筛选前&#xff1a; 选择条件&#xff1a; 筛选后&#xff1a; 返回数据格式: 代码: <el-tableref"filterTable":data"projectData.list"height"540":header-cell-style"{border-bottom: 1px soli…

单片机:实现蜂鸣器数码管的显示(附带源码)

单片机实现蜂鸣器数码管显示 蜂鸣器和数码管在嵌入式系统中广泛应用。蜂鸣器可以发出声音警告或提示&#xff0c;而数码管则用于显示数字或字母。在本项目中&#xff0c;我们将通过8051单片机实现一个控制蜂鸣器和数码管显示的系统&#xff0c;结合使用蜂鸣器和数码管&#xf…

画图,matlab,

clear;close all;clc;tic;dirOutput dir(*.dat); % 罗列所有后缀-1.dat的文件列表&#xff0c;罗列BDDATA的数据 filenames string({dirOutput.name}); % 提取文件名%% 丢包统计 FILENAMES [""]; LOSS_YTJ [ ]; LOSS_RAD [ ]; LOSS_ETH [ ]…

流程引擎Activiti性能优化方案

流程引擎Activiti性能优化方案 Activiti工作流引擎架构概述 Activiti工作流引擎架构大致分为6层。从上到下依次为工作流引擎层、部署层、业务接口层、命令拦截层、命令层和行为层。 基于关系型数据库层面优化 MySQL建表语句优化 Activiti在MySQL中创建默认字符集为utf8&…

Vue3源码笔记阅读1——Ref响应式原理

本专栏主要用于记录自己的阅读源码的过程,希望能够加深自己学习印象,也欢迎读者可以帮忙完善。接下来每一篇都会从定义、运用两个层面来进行解析 定义 运用 例子:模板中访问ref(1) <template><div>{{str}}</div> </template> <script> impo…

神经网络基础-神经网络搭建和参数计算

文章目录 1.构建神经网络2. 神经网络的优缺点 1.构建神经网络 在 pytorch 中定义深度神经网络其实就是层堆叠的过程&#xff0c;继承自nn.Module&#xff0c;实现两个方法&#xff1a; __init__方法中定义网络中的层结构&#xff0c;主要是全连接层&#xff0c;并进行初始化。…

Dcoker Redis哨兵模式集群介绍与搭建 故障转移 分布式 Java客户端连接

介绍 Redis 哨兵模式&#xff08;Sentinel&#xff09;是 Redis 集群的高可用解决方案&#xff0c;它主要用于监控 Redis 主从复制架构中的主节点和从节点的状态&#xff0c;并提供故障转移和通知功能。通过 Redis 哨兵模式&#xff0c;可以保证 Redis 服务的高可用性和自动故…

机器学习之交叉熵

交叉熵&#xff08;Cross-Entropy&#xff09;是机器学习中用于衡量预测分布与真实分布之间差异的一种损失函数&#xff0c;特别是在分类任务中非常常见。它源于信息论&#xff0c;反映了两个概率分布之间的距离。 交叉熵的数学定义 对于分类任务&#xff0c;假设我们有&#…

Scala的泛型界限

泛型界限 上限 泛型的上限&#xff0c;下限。对类型的更加具体的约束&#xff01; 如果给某个泛型设置了上界&#xff1a;这里的类型必须是上界 如果给某个泛型设置了下界&#xff1a;这里的类型必须是下界