Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

559 lines
12 KiB
C

static char sccsid[] = "@(#)91 1.9 src/bldenv/pkgtools/do_backup.c, pkgtools, bos41J, 9520A_a 5/17/95 15:01:29";
/*
* COMPONENT_NAME: PKGTOOLS
*
* FUNCTIONS: init_backup
* write_backup_eot
* write_backup_file
*
*
* ORIGINS: 3,27,9
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
*
* (C) COPYRIGHT International Business Machines Corp. 1985,1993
* All Rights Reserved
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#include "backup_io.h"
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <values.h>
/* The following declarations are used in the 'Huffman Encoding Program'
* code taken from backbyname.c and included at the end of this file.
*/
#include <sys/shm.h>
#define END 256
#define BLKSIZE BUFSIZ
#define BLKING_FACTOR 1024
#define HPACKED 017436 /* <US><RS> - Unlikely value */
unsigned char pflag = 1; /* pack files being backed up */
/* union for overlaying a long int with a set of four characters */
/* character counters */
long count [END+1];
long insize;
long filesz;
long outsize;
int diffbytes;
/* i/o stuff */
char *infile; /* unpacked file */
char inbuff [BLKSIZE];
char outbuff [BLKSIZE+4];
/* variables associated with the tree */
int maxlev;
int levcount [25];
int lastnode;
int parent [2*END+1];
/* variables associated with the encoding process */
char length [END+1];
long bits [END+1];
long mask;
long inc;
/* the heap */
int n;
struct heap {
long int count;
int node;
} heap [END+2];
#define hmove(a,b) {(b).count = (a).count; (b).node = (a).node;}
/* End of 'Huffman Encoding Program' declarations */
int init_backup(Tapeinfo *tapeinfo)
{
union fs_rec vol_rec;
if ((tapeinfo->tape_fd = open(tapeinfo->device_name, O_WRONLY|O_TRUNC|O_CREAT,
0666)) < 0) {
fprintf(stderr, "%s \n", strerror(errno));
return(-1);
}
if ((buf_start = (dword *)malloc(BLKING_FACTOR)) == NULL){
fprintf(stderr, "ERROR: Could not allocate temporary buffer space\n");
return (-1);
}
buf_ptr = buf_start;
buf_len = btow(BLKING_FACTOR);
strcpy(vol_rec.v.disk, "by name");
strcpy(vol_rec.v.fsname, "by name");
strcpy(vol_rec.v.user, "BUILD");
vol_rec.v.h.type = FS_VOLUME;
vol_rec.v.volnum = 1;
vol_rec.v.incno = BYNAME;
time(&vol_rec.v.date);
time(&vol_rec.v.dumpdate);
vol_rec.v.numwds = MAXINT;
puthdr(tapeinfo, &vol_rec, NOT_PACKED);
return (0);
}
/*
* backup this file by name
*/
int write_backup_file(Tapeinfo *tapeinfo, Fileinfo *fileinfo)
{
char buf[BSIZE];
off_t bytes;
register fd, i, j;
int aclsize, pclsize;
struct acl *aclbuf;
struct pcl *pclbuf;
struct acl taclbuf;
struct pcl tpclbuf;
int size;
int (*readfunc)();
int issymlink;
union fs_rec hdr_rec;
char *name = fileinfo->filename;
aclbuf = &taclbuf;
pclbuf = &tpclbuf;
/* make a header */
issymlink = ((fileinfo->f_st.st.st_mode & S_IFMT) == S_IFLNK);
aclsize = 16;
memset(aclbuf, 0, 16);
aclbuf->acl_len = 16;
aclbuf->acl_mode = fileinfo->f_st.st.st_mode;
aclbuf->u_access = (fileinfo->f_st.st.st_mode & 0700) >> 6;
aclbuf->g_access = (fileinfo->f_st.st.st_mode & 070) >> 3;
aclbuf->o_access = (fileinfo->f_st.st.st_mode & 07);
pclsize = 16;
memset(pclbuf, 0, 16);
pclbuf->pcl_len = 16;
pclbuf->pcl_mode = fileinfo->f_st.st.st_mode;
hdr_rec.h.type = FS_NAME_X;
hdr_rec.nx.ino = fileinfo->f_st.st.st_ino;
hdr_rec.nx.uid = fileinfo->f_st.st.st_uid;
hdr_rec.nx.gid = fileinfo->f_st.st.st_gid;
hdr_rec.nx.mode = fileinfo->f_st.st.st_mode;
hdr_rec.nx.nlink = fileinfo->f_st.st.st_nlink;
hdr_rec.nx.size = fileinfo->f_st.st.st_size;
hdr_rec.nx.atime = fileinfo->f_st.st.st_atime;
hdr_rec.nx.mtime = fileinfo->f_st.st.st_mtime;
hdr_rec.nx.ctime = fileinfo->f_st.st.st_ctime;
hdr_rec.nx.devmaj = major(fileinfo->f_st.st.st_dev);
hdr_rec.nx.devmin = minor(fileinfo->f_st.st.st_dev);
hdr_rec.nx.rdevmaj = major(fileinfo->f_st.st.st_rdev);
hdr_rec.nx.rdevmin = minor(fileinfo->f_st.st.st_rdev);
hdr_rec.nx.dsize = fileinfo->f_st.st.st_size;
i = (fileinfo->f_st.st.st_mode & S_IFMT);
if ( i == S_IFSOCK ) {
fprintf(stderr,"Adepackage: %s socket will not be backed up.\n",name);
return(0);
}
if((i != S_IFREG) && ( i != S_IFLNK)) {
if (i == S_IFDIR)
hdr_rec.nx.size = 0;
/* write header */
puthdr(tapeinfo,&hdr_rec, NOT_PACKED, name);
/* write security header */
putsechdr(tapeinfo, aclsize, pclsize);
/* write acl information */
putaclhdr(tapeinfo, aclbuf, aclsize);
/* write pcl information */
putpclhdr(tapeinfo, pclbuf, pclsize);
return (0);
}
else
if (i == S_IFLNK ) {
if (strlen(fileinfo->f_st.linkname) >= NAMESZ) {
fprintf(stderr,"Adepackage: %s filename too long\n",name);
return 0;
}
if (fileinfo->f_st.st.st_size + 1 >= NAMESZ) {
fprintf(stderr, "Adepackage: %s symbolic link too long\n",name);
return 0;
}
i = strlen(fileinfo->f_st.linkname);
hdr_rec.nx.size = i;
puthdr(tapeinfo, &hdr_rec, NOT_PACKED, name);
wmedium(tapeinfo->tape_fd, (dword *)fileinfo->f_st.linkname, btow(i));
return (0);
}
/* Open the file that we are going to back up
*
* File is already opened from main
*/
fd = fileinfo->file_fd;
/* The code below to pack the image is taken from backbyname.c */
/* If initpack fails or decides packing is not worth
* the trouble then, backup the file in the normal fashion.
* Backup according to the comments has a limitation of 24Meg.
* Actually, the limit is a file that has 24M instances of the
* same byte. We make a check here to be safest. The pack
* algorithm should be improved to remove this limitation.
*/
if (pflag && fileinfo->f_st.st.st_size &&
fileinfo->f_st.st.st_size < (24 * 1024 * 1024) &&
initpack(fd, &size))
{
int packread();
extern long outsize;
readfunc = packread;
bytes = size;
hdr_rec.nx.dsize = size;
i = PACKED;
} /* end of code from backbyname.c */
else
{
extern read();
readfunc = read;
bytes = fileinfo->f_st.st.st_size;
i = NOT_PACKED;
}
/* write header */
puthdr(tapeinfo, &hdr_rec, i, name);
/* write security header */
putsechdr(tapeinfo, aclsize, pclsize);
/* write acl information */
putaclhdr(tapeinfo, aclbuf, aclsize);
/* write pcl information */
putpclhdr(tapeinfo, pclbuf, pclsize);
while (bytes) {
register unsigned nwant;
register ngot;
nwant = min(BSIZE, bytes);
ngot = (*readfunc)(fd, buf, nwant);
if (ngot < 0) {
fprintf(stderr,"Bad read?\n"); /*p26447*/
perror(name);
ngot = 0;
perror(name);
ngot = 0;
}
if (ngot < nwant) /* changed size? */
memset(buf+ngot, 0, nwant-ngot);
wmedium(tapeinfo->tape_fd, (dword *)buf, btow(nwant));
bytes -= nwant;
}
if (i == PACKED) /* endpack is taken from backbyname.c */
endpack();
close(fd);
return (0);
}
void write_backup_eot(Tapeinfo *tapeinfo)
{
union fs_rec hdr_rec;
hdr_rec.h.type = FS_END;
puthdr(tapeinfo, &hdr_rec, NOT_PACKED);
flushmedium(tapeinfo->tape_fd);
close(tapeinfo->tape_fd);
}
/* Huffman encoding program
* Adapted April 1979, from program by T.G. Szymanski, March 1978
*/
/* gather character frequency statistics */
input ()
{
register int i;
register char *cp = infile;
for (i=0; i<END; i++)
count[i] = 0;
for(i = 0 ; i < filesz; i++)
count[*cp++ & 0377] += 2;
}
/* Function: void packerror(void)
*
* Description: The packerror() function prints out
* a message about the occurance of an internal packing
* error and exits with a non-zero return code.
*
* Return value: The function does not return.
*
* Side effects: None.
*/
void
packerror(void)
{
fprintf(stderr,
"do_backup: An internal packing error occurred.\n");
exit (1);
}
/*
* This function is coded as a co-routine of dfile.
* The state of this thread is saved in a static variable.
* The first time the function is called the thread produces
* a first block of output. The encoding tables must
* fit in this first block, this assumption is also made
* by restorx.c in its unpacking code.
*/
packread (fd, buf, nbytes)
int fd;
char *buf;
int nbytes;
{
static int firsttime = 1;
static int c, i, inleft;
static char *inp;
static char **q, *outp;
static int bitsleft;
static int j;
static int chkoutsize;
char *endbuf = buf + nbytes;
outp = buf;
if (!firsttime)
goto resume;
firsttime = 0;
chkoutsize = 0;
*outp++ = maxlev;
for (i=1; i<maxlev; i++) {
if (outp >= endbuf)
packerror();
*outp++ = levcount[i];
}
if (outp >= endbuf)
packerror();
*outp++ = levcount[maxlev]-2;
for (i=1; i<=maxlev; i++)
for (c=0; c<END; c++)
if (length[c] == i) {
if (outp >= endbuf)
packerror();
*outp++ = c;
}
/* output the text */
bitsleft = 8;
inleft = 0;
inp = infile;
for(i = 0; i <= filesz; i++)
{
c = (i == filesz)? END : *inp++ & 0377;
mask = bits[c]<<bitsleft;
if (bitsleft == 8)
*outp = (mask>>24)&0377;
else
*outp |= (mask>>24)&0377;
bitsleft -= length[c];
if (bitsleft < 0) {
j = 2;
do {
if (++outp >= endbuf) {
chkoutsize += outp - buf;
return nbytes;
}
resume:
*outp = (mask>>8*j)&0377;
j--;
bitsleft += 8;
} while (bitsleft < 0);
}
}
if (bitsleft < 8)
outp++;
firsttime = 1;
chkoutsize += outp - buf;
if (chkoutsize != outsize)
packerror();
return nbytes;
}
/* makes a heap out of heap[i],...,heap[n] */
heapify (i)
{
register int k;
int lastparent;
struct heap heapsubi;
hmove (heap[i], heapsubi);
lastparent = n/2;
while (i <= lastparent) {
k = 2*i;
if (heap[k].count > heap[k+1].count && k < n)
k++;
if (heapsubi.count < heap[k].count)
break;
hmove (heap[k], heap[i]);
i = k;
}
hmove (heapsubi, heap[i]);
}
/* return 1 after successful creation of the pack code, 0 otherwise */
int mkpackcode ()
{
register int c, i, p;
long bitsout;
/* gather frequency statistics */
input();
/* put occurring chars in heap with their counts */
diffbytes = -1;
count[END] = 1;
insize = n = 0;
for (i=END; i>=0; i--) {
parent[i] = 0;
if (count[i] > 0) {
diffbytes++;
insize += count[i];
heap[++n].count = count[i];
heap[n].node = i;
}
}
if (diffbytes == 1) {
return (0);
}
insize >>= 1;
for (i=n/2; i>=1; i--)
heapify(i);
/* build Huffman tree */
lastnode = END;
while (n > 1) {
parent[heap[1].node] = ++lastnode;
inc = heap[1].count;
hmove (heap[n], heap[1]);
n--;
heapify(1);
parent[heap[1].node] = lastnode;
heap[1].node = lastnode;
heap[1].count += inc;
heapify(1);
}
parent[lastnode] = 0;
/* assign lengths to encoding for each character */
bitsout = maxlev = 0;
for (i=1; i<=24; i++)
levcount[i] = 0;
for (i=0; i<=END; i++) {
c = 0;
for (p=parent[i]; p!=0; p=parent[p])
c++;
levcount[c]++;
length[i] = c;
if (c > maxlev)
maxlev = c;
bitsout += c*(count[i]>>1);
}
bitsout += length[END];
if (maxlev > 24) {
/* can't occur unless insize >= 2**24 */
return(0);
}
/* don't bother if no compression results */
outsize = ((bitsout+7)>>3)+1+maxlev+diffbytes;
if ((insize+BLKSIZE-1)/BLKSIZE <= ((outsize+BLKSIZE-1)/BLKSIZE)+1) {
return(0);
}
/* compute bit patterns for each character */
inc = 1L << 24;
inc >>= maxlev;
mask = 0;
for (i=maxlev; i>0; i--) {
for (c=0; c<=END; c++)
if (length[c] == i) {
bits[c] = mask;
mask += inc;
}
mask &= ~inc;
inc <<= 1;
}
return 1;
}
initpack(fd, size)
int fd;
int *size;
{
struct stat sb;
*size = 0;
if ((fstat(fd, &sb) < 0) ||
(int)(infile = shmat(fd, (char *)0, SHM_MAP|SHM_RDONLY)) < 0 ||
*(short *)infile == HPACKED)
{
return 0;
}
filesz = sb.st_size;
if(mkpackcode()) {
*size = outsize;
return 1;
}
return 0;
}
endpack()
{
if (shmdt (infile) == -1) {
perror("backup: shmdt failed\n");
exit (1);
}
}