UNIX环境高级编程APUE练习4.6-实现类似cp的程序,保留文件中的空洞
Posted 猫猫哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNIX环境高级编程APUE练习4.6-实现类似cp的程序,保留文件中的空洞相关的知识,希望对你有一定的参考价值。
1 题面
编写类似cp(1)的程序,它复制包含空洞的文件,但是不将字节0写到输出文件中去。
2 基本思路
- 首先要搞清楚空洞的性质以判断一个文件是否有空洞,以及空洞的位置
- 知道了空洞的位置之后,读到源文件中的空洞部分时,在目标文件中lseek相应的长度
3 创建空洞文件,同时探索空洞性质
交替lseek
和write
,逐渐增大间隔长度。比较文件的大小和实际占用的block数目
- 测试源码
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int holesize[]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32*1024};
int filesize = 64*1024;
int main()
{
int i = 0;
int count = 0;
int ret = 0, fd = 0;
char filename[32]={0};
unsigned char buf[32*1024]={0};
memset(buf, 1, 32*1024);
for (; i< sizeof(holesize)/ sizeof(int); ++i) {
count = 0;
memset(filename, 0, 32);
sprintf(filename, "%s%d", "holesize", holesize[i]);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(fd < 0) {
printf("open file fail
");
return -1;
}
while(count < filesize) {
ret = lseek(fd, holesize[i], SEEK_CUR);
if(ret < 0) {
printf("lseek fail
");
return -1;
}
int remain = holesize[i];
while(remain) {
ret = write(fd, buf, remain);
if(ret < 0 ) {
perror("write fail
");
return -1;
}
remain -= ret;
}
count += holesize[i] * 2;
}
close(fd);
}
return 0;
}
- MAC OSX 10.1.4.6测试结果
^_^$ ll -s
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize1
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize1024
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize128
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize16
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize16384
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize2
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize2048
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize256
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize32
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize32768
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize4
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize4096
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize512
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize64
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize8
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize8192
Mac OSX上创建不了空洞文件,因为默认的文件系统是HFS +,不支持稀疏文件
- Ubuntu18 4.15.0-60-generic测试结果
^_^$ ll -s
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize1
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize1024
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize128
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize16
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize16384
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize2
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize2048
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize256
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize32
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize32768
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize4
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize4096
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize512
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize64
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize8
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize8192
4KB以上才实际创建空洞。
因为在linux的文件系统中,磁盘分配的最小物理单元为簇。(即使文件大小不足以占用满一簇,该簇空余的磁盘存储仍旧是该文件的)
所以可以根据这个性质,判断文件是否是空洞文件。有空洞的文件,用文件大小计算的block数至少比实际占用的block数大1个簇的block数
如何可移植地获取簇的大小
pagesize = sysconf(_SC_PAGESIZE);
初步实现功能
- 源码
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/errno.h>
int my_cp(const char *from, const char *to)
{
int fd1 = -1, fd2 = -1;
int rev = -1;
unsigned char *buffer = NULL;
unsigned char *start_pos = NULL;
long pagesize = 0;
long long blocks, blksize, size;
int read_num, write_num, remain_num, current_pos = 0, last_zero = -1, last_nonzero = -1, have_holes = 0;
struct stat st;
fd1 = open(from, O_RDONLY);
if(-1 == fd1){
perror("open file1 faild");
goto err;
}
if(fstat(fd1, &st) !=0) {
perror("fstat: ");
goto err;
}
else{
#ifdef _SC_PAGESIZE
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 0) {
if (errno != 0) {
if (errno == EINVAL) {
fputs(" (not supported)
", stdout);
pagesize = st.st_blksize;
}
else {
perror("sysconf error");
goto err;
}
} else {
fputs(" (no limit)
", stdout);
pagesize = st.st_blksize;
}
}
printf("pagesize: %ld
", pagesize);
#else
pagesize = st.st_blksize;
#endif
blocks = st.st_blocks;
blksize = st.st_blksize;
size = st.st_size;
printf("st.st_blocks: %lld
", blocks);
printf("st.st_blksize: %lld
", blksize);
printf("st.st_size: %lld
", size);
/*块大小512,在不同平台上可能不兼容*/
if(S_ISREG(st.st_mode) && (size / pagesize + (size%pagesize?1:0)) * pagesize > 512 * blocks) {
have_holes = 1;
printf("%s is a sparse-block file!
", from);
} else{
have_holes = 0;
printf("%s is not a sparse-block file!
", from);
}
}
fd2 = open(to, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if ( -1 == fd2) {
perror ("open file2 faild");
goto err;
}
buffer = malloc(pagesize);
if(buffer == NULL) {
perror ("malloc fail");
goto err;
}
memset(buffer, '