通常我们复制一个文件的过程是先read后write,但是,UNIX系统具有空洞文件的特殊情况,因此不能简单地使用这种方法,否则所有的空洞会被\0填充而使得目标文件比源文件大一些(因为空洞的被填充),下面是我的代码(有参考系统命令cp的源码):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
int main ()
{
int rfd = open ("holefile", O_RDONLY);
int wfd = open ("cpholefile", O_WRONLY | O_CREAT);
int res;
struct stat statbuf;
if (fstat(rfd, &statbuf) < 0)
{
perror ("fstat");
return -1;
}
if (statbuf.st_size <= statbuf.st_blocks * 512)
{
char ch[100];
while ((res = read (rfd, ch, sizeof (ch))) != 0)
{
if (res < 0)
{
perror ("read");
return -1;
}
if (write (wfd, ch, res) != res)
{
perror ("write");
return -1;
}
}
if (fstat(wfd, &statbuf) < 0)
{
perror ("fstat");
return -1;
}
}
else
{
char c;
while ((res = read (rfd, &c, sizeof (c))) != 0)
{
if (res < 0)
{
perror ("read");
return -1;
}
if (c == 0)
{
lseek (wfd, 1, SEEK_CUR);
continue;
}
else
{
if (write (wfd, &c, 1) != 1)
{
perror ("write");
return -1;
}
}
}
}
close (rfd);
close (wfd);
return 0;
}
但是,这个程序有一下两个问题:
- 当空洞很少,即statbuf.st_size <= statbuf.st_blocks * 512时,可能造成空洞的忽略
- 当空洞与\0同时存在于一个文件中时,所有的\0都会被当作空洞处理
对于第一个问题,linux系统的处理方式是用st_size和ST_NBLOCKSIZE(磁盘实际占用空间)比较,因为ST_NBLOCKSIZE并不是POSIX.1中的标准字段,为了程序的可移植性,我没有选择使用
而第二个问题也是系统cp命令存在的问题,因为具有空洞的文件还是比较少遇到的情况,所以这个问题被UNIX系统保留了,我暂时也想不到更好的处理方法,如果有谁可以有更好的方法以克服这个问题,欢迎与我联系,谢谢!
读书笔记
技术帖
linux
unix
c++
cpp
c语言
龙潭书斋
apue
unix环境高级编程
技术分享
cp