我想分享一下我的解答,因为我觉得很多人的解答不对,他们仅仅是将空洞复制成了’\0’写入了磁盘而已。正确的方法应该是遇到’\0’就调用lseek。(假设不会有除空洞外的原因使’\0’在被读文件中存在)所以下面是我写的代码。
p.s.如果空洞很大的话,那么空洞就有存在的必要,所以只有小部分空洞真的被写入了’\0’,其他空洞只是在读出时表现为’\0’而已。(这只是我的理解)
#include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h"
int main (int argc, char **argv) {
char buf[BUFSIZ];
int src, dst, sflag, dflag, rnum, wnum;
mode_t smode, dmode;
off_t soffset, doffset;
if (argc != 3)
usageErr("Only 2 arguments are permitted");
sflag = O_RDONLY;
dflag = O_WRONLY | O_CREAT | O_TRUNC;
smode = S_IRUSR | S_IRGRP | S_IROTH;
dmode = S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IROTH;
if ((src = open(argv[1], sflag, smode)) == -1 ||
(dst = open(argv[2], dflag, dmode)) == -1)
errExit("Can't open file in arguments");
while ((rnum = read(src, buf, BUFSIZ)) > 0) {
int i = 0, mark = 0;
while(i < rnum) {
if (buf[i] == '\0') {
wnum = write(dst, &buf[mark], i-mark);
if(wnum != i-mark)
errExit("Can't write to %s", argv[2]);
int step = 1;
while (++i<rnum && buf[i] == '\0')
step++;
lseek(dst, step, SEEK_CUR);
mark = i;
}
else
i++;
}
if (mark != rnum) {
wnum = write(dst, &buf[mark], rnum-mark);
if(wnum != rnum-mark)
errExit("Can't write to %s", argv[2]);
}
}
if(rnum == -1)
errExit("Can't read %s", argv[1]);
exit(EXIT_SUCCESS);
}