/* $Id: nushar.c,v 2.2 2005/10/09 04:27:48 ksb Exp $ */ #include #include #include #include #include #include #include "main.h" #include "config.h" #include "binpack.h" #include "machine.h" #include "nushar.h" #include "shar.h" #include "tree.h" static char **ppcFiles; static int iFiles; /* record the list of files given on the command line (bj) */ void SetFiles(ac, av) int ac; char **av; { iFiles = ac; ppcFiles = av; } /* select the weight of a shar hunk for the bin packer (bj) */ VEWEIGHT CWeight(pVEnode) VE *pVEnode; { return pVEnode->iSize; } /* break the shar files up into bins and pack them (bj) * [if we are not binpacking just put them all in one] */ void PackAndShar(pVE, iVE) VE *pVE; int iVE; { int iLimit; int iFixedBinsize; int i, j, m; int bins, size; unsigned uLost; /* we're not binpacking, just shar them all in one */ if ((char *)0 == pcOutputDir) { SharStart(); if (!fNoDirTree) { for (i = 0; i < iVE; i++) MarkDirTree(pVE[i].pTdir); SharAddDirs(); } for (i = 0; i < iVE; i++) SharAddChunk(pVE[i].pcChunkFile); SharEnd(); return; } /* pack those bins! * This orders the elements into binpack order and returns num bins * We will repack to even out the bins if the last one is much * smaller than the others. */ iFixedBinsize = iBinsize - SharOverhead(); bins = VEbinpack(pVE, iVE, CWeight, iFixedBinsize, & uLost); /* count the number of shar files we *must* build */ iTotalElements += uLost + bins; iVE -= uLost; /* would repacking the bins that are left with a slightly smaller * bin size make `more even' packing? */ m = 0; for (iLimit = 0; 2 <= bins && iLimit < 10; ++iLimit) { register int allbut, iMinBinsize, slice; register int totalsize, n; auto unsigned uNewLost; size = totalsize = allbut = 0; for (i = j = 0; j < bins; j++) { allbut += size; size = 0; while (size + CWeight(pVE + i) <= iFixedBinsize && i < iVE) { size += CWeight(pVE + i); ++i; } if (0 == size) { size = CWeight(pVE + i); ++i; } totalsize += size; } /* if the last bin is < 92% of the average bin size * (other the other bins) don't bother repacking */ allbut /= bins - 1; if (14 * size >= 13 * allbut) { break; } /* how much should we take out of the other bins to * try to fill the last bin up a little more? */ slice = (allbut - size)/bins; #if 0 printf("stats: %d bytes in %d bins of %d [average %d] + %d\n", totalsize, bins, iFixedBinsize, allbut, size); printf("moving %d bytes, take %d from adjusted binsize\n", slice * (bins - 1), slice); fflush(stdout); #endif /* we can't make any new bins, but we can shuffle the * partial bins around to make them all the same size */ m = allbut - slice; do { iMinBinsize = m + 1; m = (iFixedBinsize + iMinBinsize) >> 1; n = VEbinpack(pVE, i, CWeight, m, & uNewLost); } while (n + uNewLost != bins); iFixedBinsize = m; uLost += uNewLost; iVE -= uNewLost; bins -= uNewLost; } #if 0 if (0 != m) { printf("%s: repacked some bins with -B %d\n", progname, m + SharOverhead()); } #endif for (i = j = 0; j < bins; j++) { int iStart, k; iElementNumber = j + 1; SharStart(); /* find the range of this bin */ size = 0; iStart = i; while (size + CWeight(pVE + i) <= iFixedBinsize && i < iVE) { size += CWeight(pVE + i); MarkDirTree(pVE[i].pTdir); i++; } SharAddDirs(); /* now add the files in this bin */ for (k = iStart; k < i; k++) { SharAddChunk(pVE[k].pcChunkFile); } SharEnd(); } /* give each oversize file it's own shar file */ iVE += uLost; for (; i < iVE; i++, j++) { iElementNumber = j + 1; SharStart(); MarkDirTree(pVE[i].pTdir); SharAddDirs(); SharAddChunk(pVE[i].pcChunkFile); SharEnd(); } } void addToVec(piAc, pppcAv, fp, pcFile) int *piAc; char ***pppcAv; FILE *fp; char *pcFile; { char **ppcNewAv; int n, iSize; char acBuf[MAXPATHLEN+1]; iSize = n = 0; ppcNewAv = NULL; while (fgets(acBuf, MAXPATHLEN, fp)) { char *pcNL = acBuf + strlen(acBuf) - 1; if ('\n' != *pcNL) { fprintf(stderr, "%s: filename in %s too long\n", progname, pcFile); exit(1); } *pcNL = '\000'; if (n == iSize) { iSize += 100; if (ppcNewAv) ppcNewAv = (char **) realloc(ppcNewAv, sizeof(char *) * iSize); else ppcNewAv = (char **) malloc(sizeof(char *) * iSize); } ppcNewAv[n++] = strdup(acBuf); } if (!n) { return; } if (*piAc) { char **ppcResultAv; int i; ppcResultAv = (char **) malloc(sizeof(char *) * (n + *piAc + 1)); for (i = 0; i < *piAc; i++) ppcResultAv[i] = (*pppcAv)[i]; for (i = 0; i < n; i++) ppcResultAv[i + *piAc] = ppcNewAv[i]; free(ppcNewAv); /* don't free the passed Av? */ *pppcAv = ppcResultAv; *piAc += n; } else { *pppcAv = (char **) realloc(ppcNewAv, sizeof(char *) * (n + 1)); *piAc = n; } (*pppcAv)[*piAc] = NULL; } int DoNushar() { int i, j; VE *pVE; if (pcInputFile) addToVec(&iFiles, &ppcFiles, pfInputFile, pcInputFile); if (0 == iFiles) { fprintf(stderr, "%s: no input files\n", progname); exit(1); } pVE = (VE *) malloc(sizeof(struct VEnode) * iFiles); for (i = j = 0; i < iFiles; i++) { struct stat sBuf; if (lstat(ppcFiles[i], &sBuf) < 0) { fprintf(stderr, "%s: lstat: %s: %s\n", progname, ppcFiles[i], strerror(errno)); exit(1); } /* we now create dirs as needed in every shar part */ if (S_ISDIR(sBuf.st_mode)) continue; pVE[j].pcName = ppcFiles[i]; /* create the temp file that has this file shar-wrapped */ if ((char *)0 != (pVE[j].pcChunkFile = SharMakeChunk(ppcFiles[i], &(pVE[j].iSize), &sBuf))) { pVE[j].pTdir = (fNoDirTree) ? NULL : pTfindDirTree(ppcFiles[i]); j++; } } PackAndShar(pVE, j); return 0; }