
SerenityOS truncate 命令完全指南用法、实现原理与源码解析【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenitytruncate是 SerenityOS 系统自带的核心文件工具之一用于将目标文件扩展或缩小到指定大小是创建稀疏文件、预分配磁盘空间、快速清空文件或按参考文件对齐尺寸的常用手段。本文以仓库中的官方手册 truncate.md 为主体结合其 C 实现 truncate.cpp、LibC 系统调用封装与内核 ftruncate 实现帮助你从怎么用到底层发生了什么完整掌握这个工具。Name名称truncate—— 调整文件大小Resize a file。Synopsis语法$ truncate [--size size] [--reference file] file其中size为大小参数file为目标文件路径。--size与--reference二者必须且只能提供其一详见下文参数互斥约束。Options选项选项简写说明--size size-s size将目标文件调整为或增减该大小。前缀表示在现有大小基础上扩展前缀-表示在现有大小基础上缩小裸数字则精确设置文件大小--reference file-r file将目标文件的大小调整为与指定参考文件一致Arguments参数file目标文件路径。用法详解与实战示例1. 精确设置文件大小OP_Set不带任何/-前缀、直接给出数字时truncate会把文件大小精确地设置为该值对应源码中的OP_Set分支$ truncate -s 100 data.bin若文件原本小于 100 字节则被扩展扩展出的部分在磁盘上通常不实际占用数据块形成稀疏文件若文件原本大于 100 字节则超出部分被丢弃。2. 相对扩展文件OP_Grow使用前缀在现有大小基础上增加指定字节数对应源码OP_Grow$ truncate -s 4096 data.bin上述命令把data.bin的当前大小增加 4096 字节。从源码看最终目标大小计算为stat.st_size sizecase OP_Grow: size stat.st_size size; break;truncate.cpp3. 相对缩小文件OP_Shrink使用-前缀在现有大小基础上减少指定字节数对应OP_Shrink$ truncate -s -512 data.bin注意缩小操作的结果不会小于 0 —— 源码使用max(stat.st_size - size, 0)做了下限保护即使减到负数也会被钳制为 0case OP_Shrink: size max(stat.st_size - size, 0); break;truncate.cpp4. 按参考文件调整大小-r选项读取参考文件的st_size并把目标文件调整为相同大小$ truncate -r template.bin output.bin源码通过Core::System::stat(reference)取得参考文件大小再对目标文件执行ftruncateif (!reference.is_empty()) { auto stat TRY(Core::System::stat(reference)); size stat.st_size; }truncate.cpp5. 单位后缀支持大小参数支持k、m、g三种二进制单位后缀不区分大小写分别对应 KiB1024、MiB1024²、GiB1024³。例如$ truncate -s 10m disk.img # 设置为 10 MiB10485760 字节 $ truncate -s 1g big.bin # 在现有大小上增加 1 GiB源码中的后缀解析逻辑如下truncate.cppauto suffix resize[resize.length() - 1]; i64 multiplier 1; if (!AK::is_ascii_digit(suffix)) { switch (to_ascii_lowercase(suffix)) { case k: multiplier KiB; resize resize.substring_view(0, resize.length() - 1); break; case m: multiplier MiB; ... case g: multiplier GiB; ... default: args_parser.print_usage(stderr, arguments.strings[0]); return 1; } }除k/m/g之外的任何非数字后缀都会导致命令失败并打印用法信息因此-s 10x这类写法会直接报错。6. 清空文件将文件设置为 0 字节是最常见的用途之一例如在日志轮转或测试脚本中快速清空文件内容$ truncate -s 0 app.log参数互斥与校验约束源码在参数解析之后做了严格校验truncate.cppif (resize.is_empty() reference.is_empty()) { args_parser.print_usage(stderr, arguments.strings[0]); return 1; } if (!resize.is_empty() !reference.is_empty()) { args_parser.print_usage(stderr, arguments.strings[0]); return 1; }也就是说两个参数都不给打印 usage 并返回退出码 1两个参数同时给同样打印 usage 并返回退出码 1二者必须恰好提供一个。此外数值解析使用了Checkedoff_t::multiplication_would_overflow做溢出检查truncate.cpp当数值与单位乘数相乘会溢出off_t时命令会失败避免异常的大尺寸导致未定义行为。底层实现原理从用户态到内核用户态封装LibCore::Systemtruncate工具通过LibCore的Core::System封装调用系统调用System.h 声明ErrorOrvoid ftruncate(int fd, off_t length);System.cpp 中将其包装为对::ftruncate的系统调用失败时返回携带 errno 的ErrorErrorOrvoid ftruncate(int fd, off_t length) { if (::ftruncate(fd, length) 0) return Error::from_syscall(ftruncatesv, -errno); return {}; }工具本身先以O_RDWR | O_CREAT打开目标文件权限掩码0666再调用ftruncate并关闭文件truncate.cpp。这意味着目标文件不存在时会被自动创建而存在时则直接就地调整大小。LibC 接口truncate与ftruncate两个经典 POSIX 接口在 unistd.h 中声明int ftruncate(int fd, off_t length); int truncate(char const* path, off_t length);内核侧sys$ftruncate内核系统调用实现位于 ftruncate.cpp它做了三类关键检查ErrorOrFlatPtr Process::sys$ftruncate(int fd, off_t length) { VERIFY_NO_PROCESS_BIG_LOCK(this); TRY(require_promise(Pledge::stdio)); if (length 0) return EINVAL; auto description TRY(open_file_description(fd)); if (!description-is_writable()) return EBADF; TRY(description-truncate(static_castu64(length))); return 0; }负长度直接返回EINVAL文件描述符不可写返回EBADF对应 LibC 测试ftruncate_readonly中的预期行为通过文件描述符对应的OpenFileDescription::truncate(u64)声明于 OpenFileDescription.h下发到具体文件系统执行。该调用在 Syscall.h 中登记为S(ftruncate, ...)进程还须具备Pledge::stdio承诺才能执行——这也是 truncate 工具启动时调用pledge(stdio rpath wpath cpath)truncate.cpp的原因它同时声明了打开参考文件所需的rpath与创建/写入目标文件所需的wpath、cpath。文件系统层面稀疏文件语义内核测试 TestPageFaultRace.cpp 的注释明确说明了这一点Using ftruncate should cause this to be a sparse file, so it shouldnt take up any disk (or rather RAMFS) space.即通过ftruncate将文件扩展到大尺寸时新增长度对应的区块在底层通常以空洞hole形式存在不立即占用实际存储空间这也正是用truncate预分配大文件如磁盘镜像时开销极小的原因。与 C 库 API 测试的印证仓库中的测试用例从多个角度验证了 truncate/ftruncate 的语义TestTruncate.cpp对不存在的路径调用truncate()返回负值且errno ENOENTTestIo.cpp以只读方式打开的文件调用ftruncate得到EBADF负长度得到EINVALTestLibCoreStream.cppCore::File::truncate()先将文件调整为 999 字节、再调整为 42 字节均能正确反映到size()stress-truncate.cpp内核压力测试中循环把文件截断为随机大小用于验证极端场景下的稳定性。此外truncate 工具本身在 Userland/Utilities/CMakeLists.txt 中注册构建随系统一起编译安装。使用注意与限制数据不可恢复缩小操作会永久丢弃超出部分的数据执行前请确认不需要备份仅支持二进制单位k/m/g对应 KiB/MiB/GiB不存在 KB/MB/GB十进制后缀混用十进制习惯可能导致实际分配大小与预期不符空参数组合会报错-s与-r必须二选一同时使用或不使用都会打印 usage 并以退出码 1 结束无参数直接运行同样打印 usage自动创建文件目标文件不存在时会以0666权限受进程 umask 影响自动创建适合在脚本中确保文件存在并设置大小该手册由 ArgsParser 自动生成文档末尾标注!-- Auto-generated through ArgsParser --选项说明与 truncate.cpp 中add_option的注释文本一一对应。参考文档官方手册Base/usr/share/man/man1/truncate.md工具实现Userland/Utilities/truncate.cppLibC 接口声明Userland/Libraries/LibC/unistd.h系统调用封装Userland/Libraries/LibCore/System.cpp内核实现Kernel/Syscalls/ftruncate.cpp文件描述符截断接口Kernel/FileSystem/OpenFileDescription.h【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考