Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Chapter-04/make_sparse_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int main()
{
int fd = open("sparse_file", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open failed");
return -1;
}
off_t offset = 1024 * 1024; // 1MB
for(int i = 0; i < 10; i++)
{
// 将文件指针向后移动到 1MB 位置(创建空洞)
if (lseek(fd, offset - 1, SEEK_CUR) == -1) {
perror("lseek failed");
close(fd);
return -1;
}

// 写入一个字节,使文件实际大小为 1MB(前 1MB-1 是空洞)
write(fd, "a", 1);
}

close(fd);
return 0;
}

85 changes: 55 additions & 30 deletions Chapter-04/p6.c
Original file line number Diff line number Diff line change
@@ -1,57 +1,82 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>


#define BUF_SIZE 4096

int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage: ./a.out file1 file2\n");
int main(int argc, char* argv[])
{
if(argc < 3){
printf("Usage: %s source_file dest_file\n", argv[0]);
exit(1);
}

char buff[BUF_SIZE];
int fd1, fd2;
if ((fd1 = open(argv[1], O_RDWR)) == -1) {
printf("open %s failure\n", argv[1]);
char buf[BUF_SIZE];

if((fd1 = open(argv[1], O_RDONLY)) == -1){
perror("open source file");
exit(1);
}
if ((fd2 = open(argv[2], O_RDWR | O_CREAT, 0666)) == -1) {
printf("open %s failure\n", argv[2]);

if((fd2 = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1){
perror("open dest file");
exit(1);
}

int cnt, i, all_cnt = 0;
int f, l;
while ((cnt = read(fd1, buff, BUF_SIZE))) {
f = l = 0;
for (i = 0; i < cnt; i++) {
if (f == 0 && buff[i] != 0) { // 如果在空洞状态遇到非空洞,则记录下来位置, lseek 调整位置
l = i;
f = 1;
if (lseek(fd2, all_cnt + i, SEEK_SET) == -1) {
printf("lseek failure\n");
ssize_t nread;
off_t file_pos = 0; // 源文件中的当前位置
int in_hole = 1; // 初始状态为空洞(文件开头可能是空洞)
off_t data_start = 0; // 当前数据块的开始位置
off_t hole_start = 0; // 当前空洞的开始位置

while((nread = read(fd1, buf, BUF_SIZE)) > 0){
for(int i = 0; i < nread; i++){
if(buf[i] != 0 && in_hole){
// 非0字节 - 数据部分,从空洞切换到数据
in_hole = 0;
data_start = file_pos + i;
// 移动到数据开始位置
if(lseek(fd2, data_start, SEEK_SET) == -1){
perror("lseek");
exit(1);
}
} else if (f != 0 && buff[i] == 0) { // 如果在非空洞状态遇到空洞,则将之前的非空洞序列复制
if (write(fd2, buff + l, i - l) == -1) {
printf("fd2 write failure\n");
}
if(buf[i] == 0 && !in_hole)
{
// 0字节 - 空洞部分,从数据切换到空洞
in_hole = 1;
hole_start = file_pos + i;
// 写入之前的数据块
if(write(fd2, buf + (data_start - file_pos),
hole_start - data_start) == -1){
perror("write");
exit(1);
}
f = 0;
}
}
if (l != cnt) { // 将没有复制过去的所有都复制过去
if (write(fd2, buff + l, cnt - l) == -1) {
printf("fd2 write failure\n");
exit(1);
}
file_pos += nread;
}

// 处理文件末尾可能的数据块
if(!in_hole){
// 文件以数据结束
if(write(fd2, buf + (data_start - (file_pos - nread)),
file_pos - data_start) == -1){
perror("write");
exit(1);
}
all_cnt += cnt;
}

// 确保目标文件大小正确
if(ftruncate(fd2, file_pos) == -1){
perror("ftruncate");
exit(1);
}

close(fd1);
close(fd2);
return 0;
}