《APUE.3E》习题4.6编写自己的cp(l)程序,它复制包含空洞的文件,但不将字节0包含到输出文件中去

Posted 啊啊啊西吧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《APUE.3E》习题4.6编写自己的cp(l)程序,它复制包含空洞的文件,但不将字节0包含到输出文件中去相关的知识,希望对你有一定的参考价值。

1、产生空洞的方式lseek()

#include "apue.h"
#include <fcntl.h>

char    buf1[] = "abcdefghij";
char    buf2[] = "ABCDEFGHIJ";

int
main(void)

    int fd;

    /* 创建一个文件 */
    if ((fd = creat("file.hole", FILE_MODE)) < 0)
        err_sys("creat error");

    /* 写入第一部分内容 */
    if (write(fd, buf1, 10) != 10)
        err_sys("buf1 write error");
    /* offset now = 10 */

    /* 重设当前偏移量, 超过文件长度 */
    if (lseek(fd, 16384, SEEK_SET) == -1)
        err_sys("lseek error");
    /* offset now = 16384 */

    /* 写入第二部分 */
    if (write(fd, buf2, 10) != 10)
        err_sys("buf2 write error");
    /* offset now = 16394 */

    exit(0);

2、通过看cp命令的源码,可以看到cp的具体过程:

1、 判断目标文件是否存在,如果存在则清空目标文件,如果不存在则创建目标文件
2、根据目标文件的逻辑块大小,创建拷贝缓冲区
3、判断源文件是否有空洞:文件大小/文件块大小 > 块数 ?
4、读取源文件存放到缓冲区,每次读取一块
5、在第3步中判断,如果存在文件空洞,则对缓冲区数据进行判断,如果缓冲区中的数据均为0,则认为该数据快为空洞,否则认为是正常文件数据
6、如果数据块为空洞,则调用lseek,在目标文件中创建一个空洞;否则拷贝缓冲区数据到目标文件
7、判断本次读取是否读到源文件的文件尾,如果是,则判断本次读取的是否是空洞,如果是空洞则在文件的最后写入””
8、重复1 ~ 7
9、关闭目标文件、源文件

cp一个有空洞的文件,发现cp前后占用的磁盘大小未变,而scp到另一台机器后,空洞被填满,占用磁盘块变大。

3、编写自己的cp命令

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>

#define BUF_SIZE 4096

int my_cp(const char *file1, const char *file2)

    int fd1, fd2;
    char buffer[BUF_SIZE];
    int res, current_position = 0, byte_count =0, have_holes = 0;
    struct stat st;

    fd1 = open(file1, O_RDWR);
    if(-1 == fd1)
        perror("open file1 faild");
        return -1;
    

    if(fstat ( fd1, &st) !=0)
        perror("fstat");
    else
        if (S_ISREG(st.st_mode) && st.st_size > 512 * st.st_blocks) 
            have_holes = 1;
            printf("%s is a sparse-block file!\\n", file1);
         else 
            have_holes = 0;
            printf("%s is not a sparse-block file!\\n", file1);
        
    

    fd2 = open(file2, O_RDWR | O_APPEND | O_CREAT | O_TRUNC, 0666);
    if ( -1 == fd2) 
        perror ("open file2 faild");
        return -1;
    

    memset(buffer, '\\0', BUF_SIZE);
    res = read(fd1, buffer, BUF_SIZE);//返回读到的字节数
    if ( -1 == res) 
        perror ("file1 read error");
        return -1;
    

    if(have_holes)
        byte_count =0;
        for (current_position = 0; current_position < res; current_position ++) 

            if (0 != buffer[current_position] )
            
                    buffer[byte_count] = buffer[current_position];
                    byte_count ++;
            
        
    else
        byte_count = res;

    res = write(fd2, buffer, byte_count);
    if ( -1 == res)
        perror( " file2 write error");
        return -1;
    

    close(fd1);
    close(fd2);



int main(int argc, char * argv[])

    if (3 != argc)
        printf("usage error : ./a.out file1 file2\\n");
        return -1;
    
    int res = my_cp(argv[1], argv[2]);
    if ( -1 == res) 
        perror (" my_cp error");
        return -1;
    

    exit(0);

该cp命令最多复制4096字节,但根据对比文件的大小与实际占用block的大小确实可以确定shifou存在空洞

以上是关于《APUE.3E》习题4.6编写自己的cp(l)程序,它复制包含空洞的文件,但不将字节0包含到输出文件中去的主要内容,如果未能解决你的问题,请参考以下文章

unix 环境高级编程第三版 源码无法 make 成功, 对‘heapsort’未定义的引用 -apue.3e

CentOS 7如何安装 libbsd-dev && 编译apue.3e时出错处理(以便使用Unix环境高级编程中的apue.h库)

Linux安装apue.3e(基于ubuntu16.0.4)

《UNIX环境高级编程》源码配置——apue.3e 安装

Python练习题4.6输出前 n 个Fibonacci数

UNIX环境高级编程APUE练习4.6-实现类似cp的程序,保留文件中的空洞