/* Sparsify.c
J.H. Davenport 21.5.89
usage: "sparsify filename"
The file-name had better not be a symbolic link,
but this isn't checked for.
Modification: JHD 25.7.89: set owner (where possible)
modification times, permission status etc.
Modification: JHD 16.10.89: fix a SUNos 4 feature for files whose
last block is precisely null
*/
#define BSIZE 8192
#ifdef hpux
#include <fcntl.h>
/* This will give us O_RDONLY and friends on HPUX */
#include <utime.h>
struct utimbuf hpux_utime;
#endif
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
long lseek();
char *malloc();
/* Really should look it up: could be something different, but it
doesn't really matter */
int buf[BSIZE/4]; /* So can use word operations */
main(argc,argv)
int argc;
char **argv;
{ int ifile,ofile,ilen,ans,seeking;
long lans;
char *oname;
struct stat statbuf;
if (argc != 2)
{ printf("Usage: sparsify filename\n");
exit(-1);
}
ifile=open(argv[1],O_RDONLY);
if (ifile<0)
{ perror("File couldn't be opened\n");
exit(ifile);
}
oname=malloc((ilen=strlen(argv[1]))+3);
strcpy(oname,argv[1]);
oname[ilen]='.';
oname[ilen+1]='z';
oname[ilen+2]='\0';
ofile=open(oname,O_WRONLY|O_CREAT|O_EXCL,0755);
if (ofile<0)
{ perror("Output file couldn't be opened\n");
exit(ifile);
}
seeking=0;
while ((ilen=read(ifile,(char *)buf,BSIZE))==BSIZE)
if (allzeros())
{ lans=lseek(ofile,(long)BSIZE,L_INCR);
if(lans<0)
{ perror("Lseek failed\n");
tidyup(oname);
}
seeking=1;
}
else
{ ans=write(ofile,(char *)buf,BSIZE);
if (ans != BSIZE)
{ perror("Write failed\n");
tidyup(oname);
}
seeking=0;
}
if (ilen > 0)
{ ans=write(ofile,(char *)buf,ilen);
if (ans != ilen)
{ perror("Write failed\n");
tidyup(oname);
}
}
else if (seeking)
{ lans=lseek(ofile,-(long)BSIZE,L_INCR);
if(lans<0)
{ perror("Lseek failed\n");
tidyup(oname);
}
ans=write(ofile,(char *)buf,BSIZE);
if (ans != BSIZE)
{ perror("Write failed\n");
tidyup(oname);
}
}
ilen=fstat(ifile,&statbuf);
if (ilen < 0)
{ perror("Fstat failed\n");
tidyup(oname);
}
ilen=fchmod(ofile,statbuf.st_mode);
if (ilen < 0)
{ perror("Attempt to chmod failed\n");
tidyup(oname);
}
if (geteuid())
{ if (statbuf.st_uid != geteuid())
printf("Can't reset owner/group\n");
}
else {
ilen=fchown(ofile,statbuf.st_uid,statbuf.st_gid);
if (ilen < 0)
{ perror("Chown failed\n");
tidyup(oname);
}
}
#ifdef hpux
/* So it's hpux */
hpux_utime.actime=statbuf.st_atime;
hpux_utime.modtime=statbuf.st_mtime;
ilen=utime(oname,&hpux_utime);
#else
/* so it's a sun, or maybe an apollo */
ilen=utimes(oname,&statbuf.st_atime);
#endif
if (ilen < 0)
{ perror("Attempt to set times failed\n");
tidyup(oname);
}
ilen=unlink(argv[1]);
if (ilen<0)
{ perror("Unlink for old file failed\n");
printf("Tidy up by hand!\n");
exit(-1);
}
ilen=link(oname,argv[1]);
if (ilen!= 0)
{ perror("Rename failed\n");
printf("Tidy up by hand!\n");
exit(-1);
}
ilen=unlink(oname);
if (ilen<0)
{ perror("Unlink for temporary file failed\n");
printf("Tidy up by hand!\n");
exit(-1);
}
exit(0);
}
tidyup(oname)
char *oname;
{ int ilen;
ilen=unlink(oname);
if (ilen<0)
{ perror("Unlink for temporary file failedwhile tidying up\n");
printf("Tidy up by hand!\n");
exit(-1);
}
}
allzeros()
{ int i;
for(i=0;i<BSIZE/4;i++)
if(buf[i])
return 0;
return 1;
}