Exemple #1
0
int 
pe2ps_aux (PS ps, PE pe, int eval)
{
	int     result;

	if (eval > 0)
		switch (pe -> pe_form) {
		case PE_FORM_PRIM:
		case PE_FORM_ICONS:
			break;

		case PE_FORM_CONS:
			 ps_get_abs (pe);
			break;
		}

	if ((result = pe2ps_aux2 (ps, pe, eval)) != NOTOK)
		result = ps_flush (ps);

	return result;
}
Exemple #2
0
static int  putaux (char* src, char* dst, int append, int fd, PE pe,struct vfsmap*vf, int size)
#endif
{
	int    n;
	int     cc,
			effector,
			gd,
			nc,
			reason,
			result;
	PE	    de,
	 param;
#ifdef	BRIDGE
	char line[BUFSIZ];
#endif
	struct FADUidentity faduids;
	struct FADUidentity   *faduid = &faduids;
	struct FTAMgroup    ftgs;
	struct FTAMgroup  *ftg = &ftgs;
	struct FTAMindication   ftis;
	struct FTAMindication *fti = &ftis;
	struct FTAMabort  *fta = &fti -> fti_abort;
	FILE *fp;

	pe -> pe_context = vf -> vf_id;

	param = NULLPE;
	if (vf -> vf_parameter
			&& enc_f (vf -> vf_number, &_ZDOCS_mod, &param, 1, 0, NULLCP,
					  vf -> vf_parameter) == NOTOK) {
		advise (NULLCP, "unable to build document type parameter: %s",
				PY_pepy);
		return NOTOK;
	}

	bzero ((char *) ftg, sizeof *ftg);
	ftg -> ftg_flags |= FTG_BEGIN | FTG_END;
	ftg -> ftg_threshold = 0;

	if (omode == FOVER_SELECT)
		append = 1;
	if (units & FUNIT_LIMITED) {
		ftg -> ftg_flags |= FTG_CREATE;
		{
			struct FTAMcreate *ftce = &ftg -> ftg_create;
			struct FTAMattributes *fa = &ftce -> ftce_attrs;

			ftce -> ftce_override = append ? FOVER_SELECT : omode;

			fa -> fa_present = FA_FILENAME;
			fa -> fa_nfile = 0;
			fa -> fa_files[fa -> fa_nfile++] = dst;

			fa -> fa_present |= FA_ACTIONS;
			fa -> fa_permitted = FA_PERM_READ | FA_PERM_REPLACE
								 | FA_PERM_EXTEND | FA_PERM_READATTR
								 | FA_PERM_CHNGATTR | FA_PERM_DELETE
								 | FA_PERM_TRAV;

			fa -> fa_present |= FA_CONTENTS;
			fa -> fa_contents = vf -> vf_oid;
			fa  -> fa_parameter = param;

			ftce -> ftce_access = append ? FA_PERM_EXTEND : FA_PERM_REPLACE;
			FCINIT (&ftce -> ftce_conctl);
		}
	} else {
		ftg -> ftg_flags |= FTG_SELECT;
		{
			struct FTAMselect *ftse = &ftg -> ftg_select;
			struct FTAMattributes *fa = &ftse -> ftse_attrs;

			if (!append && omode == FOVER_FAIL) {
				advise (NULLCP,
						"lack of limited-file-management conflicts with setting of \"override\" variable");
				return NOTOK;
			}

			fa -> fa_present = FA_FILENAME;
			fa -> fa_nfile = 0;
			fa -> fa_files[fa -> fa_nfile++] = dst;

			ftse -> ftse_access = append ? FA_PERM_EXTEND : FA_PERM_REPLACE;
			FCINIT (&ftse -> ftse_conctl);
		}
	}

	ftg -> ftg_threshold++;

	ftg -> ftg_flags |= FTG_OPEN;
	{
		struct FTAMopen   *ftop = &ftg -> ftg_open;

		ftop -> ftop_contents = vf -> vf_oid;
		ftop -> ftop_parameter = param;
		FCINIT (&ftop -> ftop_conctl);
		if (append) {
			ftop -> ftop_mode = FA_PERM_EXTEND;
			if (concurrency)
				ftop -> ftop_conctl.fc_extendlock = FLOCK_EXCLUSIVE;
		} else {
			ftop -> ftop_mode = FA_PERM_REPLACE;
			if (concurrency)
				ftop -> ftop_conctl.fc_replacelock = FLOCK_EXCLUSIVE;
		}
	}
	ftg -> ftg_threshold++;

	result = FBulkBeginRequest (ftamfd, ftg, fti);

	if (param)
		pe_free (param);

	if (result == NOTOK) {
		ftam_advise (fta, "F-BULK-BEGIN.REQUEST");
		return NOTOK;
	}

	ftg = &fti -> fti_group;

	if (ftg -> ftg_flags & FTG_SELECT) {
		struct FTAMselect *ftse = &ftg -> ftg_select;

		ftam_diag (ftse -> ftse_diags, ftse -> ftse_ndiag, 1,
				   ftse -> ftse_action);
		if (ftse -> ftse_state != FSTATE_SUCCESS)
			goto you_lose;
	} else if (ftg -> ftg_flags & FTG_CREATE) {
		struct FTAMcreate *ftce = &ftg -> ftg_create;

		ftam_diag (ftce -> ftce_diags, ftce -> ftce_ndiag, 1,
				   ftce -> ftce_action);
		if (ftce -> ftce_state != FSTATE_SUCCESS)
			goto you_lose;
	}

	if (ftg -> ftg_flags & FTG_OPEN) {
		struct FTAMopen   *ftop = &ftg -> ftg_open;

		ftam_diag (ftop -> ftop_diags, ftop -> ftop_ndiag, 1,
				   ftop -> ftop_action);
		if (ftop -> ftop_state != FSTATE_SUCCESS)
			goto you_lose;

		for (myvf = vfs; myvf -> vf_entry; myvf++)
			if (oid_cmp (myvf -> vf_oid, ftop -> ftop_contents) == 0)
				break;
		switch (myvf - vfs) {
		case VFS_UTF:
			pe -> pe_id = (PElementID)
						  ((struct type_DOCS_FTAM__1__Parameters *)
						   myvf -> vf_parameter)
						  -> universal__class__number;
		/* and fall... */
		case VFS_UBF:
			effector = 1;
			if (ftop -> ftop_parameter && myvf -> vf_number >= 0) {
				caddr_t parm = NULL;

				if (dec_f (myvf -> vf_number, &_ZDOCS_mod,
						   ftop -> ftop_parameter, 1, NULLIP, NULLVP,
						   &parm) == NOTOK)
					advise (NULLCP,
							"unable to parse document type parameter: %s",
							PY_pepy);
				else
					switch (myvf - vfs) {
					case VFS_UTF: {
						struct type_DOCS_FTAM__1__Parameters *p1 =
							(struct type_DOCS_FTAM__1__Parameters *)
							parm;

						if (p1 -> optionals
								& opt_DOCS_FTAM__1__Parameters_universal__class__number)
							pe -> pe_id = (PElementID)
										  p1 -> universal__class__number;
						else
							pe -> pe_id = PE_DEFN_GFXS;
						switch (pe -> pe_id) {
						case PE_DEFN_GFXS:
							if (getenv ("HP-FTAM")) {
								effector = 1;
								break;
							}	/* else fall... */
						case PE_DEFN_PRTS:
						case PE_DEFN_VISS:
							effector = 0;
							break;

						case PE_DEFN_T61S:
						case PE_DEFN_VTXS:
						case PE_DEFN_IA5S:
						case PE_DEFN_GENS:
							effector = 1;
							break;

						default:
							break;
						}
					}
					break;

					case VFS_UBF:
					default:
						break;
					}
				if (parm)
					 fre_obj (parm,
									_ZDOCS_mod.md_dtab[myvf -> vf_number],
									&_ZDOCS_mod, 1);
			}
			if (debug)
				advise (NULLCP, "effector=%d id=0x%x",
						effector, pe -> pe_id);
			if (myvf != vf || watch) {
				advise (NULLCP, "%s transfer", myvf -> vf_text);
				vf = myvf;
			}
			break;

		default:
			vf = &vfs[VFS_UBF];
			advise (NULLCP, "document type mismatch; assuming %s (%s)",
					vf -> vf_text, vf -> vf_entry);
			break;
		}
	}
	myvf = vf;

	FTGFREE (ftg);

	faduid -> fa_type = FA_FIRSTLAST;
	faduid -> fa_firstlast = FA_FIRST;
	if (FReadWriteRequest (ftamfd, append ? FA_OPS_EXTEND : FA_OPS_REPLACE,
						   faduid, myvf -> vf_context, NOTOK, 0, fti) == NOTOK) {
		ftam_advise (fta, "F-READWRITE.REQUEST");
		return NOTOK;
	}

	switch (myvf - vfs) {
	case VFS_UTF:
		if ((gd = dup (fd)) == NOTOK || (fp = fdopen (gd, "r")) == NULL) {
			if (gd != NOTOK)
				 close (gd);

#ifdef	BRIDGE
			advise (dst, gd != NOTOK ? "fdopen failed" : "unable to dup");
#else
			advise (src, gd != NOTOK ? "fdopen failed on"
					: "unable to dup");
#endif
			reason = FS_ACC_LCL;
			goto do_cancel;
		}
		break;

	case VFS_UBF:
	default:
		fp = NULL;
		break;
	}

	cc = 0;
	if (verbose)
		timer (cc, NULLCP);
	if (hash)
		marks = BUFSIZ - 1;

#ifdef	BRIDGE
	line[0] = '\0';
#endif

	for (;;) {
		char  *bp,
				 *ep;

		if (!interrupted) {
			int	    nfds;
			fd_set  wfds;

			nfds = 0;
			FD_ZERO (&wfds);
			/* interrupt causes EINTR */
			if (FSelectMask (ftamfd, &wfds, &nfds, fti) == OK)
				 xselect (nfds, NULLFD, &wfds, NULLFD, NOTOK);
		}

		if (interrupted) {
			advise (NULLCP, "cancelling transfer");

			reason = FS_GEN_INITIATOR;
			errno = EINTR;
			goto do_cancel;
		}

		for (ep = (bp = (char *) pe -> pe_prim) + size - (fp ? 2 : 0), nc = 0;
				bp < ep; ) {
			if (fp) {
				char  *cp;

#ifdef	BRIDGE
				if (strlen (line) || fgets (line, BUFSIZ, fp)) {
					if ((int)(strlen(line) + 1) < (ep - bp - 1)) {
						 strcpy (bp, line);
						line[0] = NULL;
					} else
						break;
				} else {
#else
				if (fgets (bp, ep - bp + 1, fp) == NULL) {
#endif
					n = (ferror (fp) && !feof (fp)) ? NOTOK : OK;
					break;
				}
				cp = bp + strlen (bp) - 1;
				if (!effector) {
					if (*cp == '\n') {
#ifndef	BRIDGE
						*cp = NULL;
#else
						if (cp > bp) {
							if (*--cp == '\r')
								*cp = NULL;
							else
								*++cp = NULL;
						} else
							*cp = NULL;
#endif
						n = cp - bp;
						bp = cp;
					} else {			/* XXX: losing! */
						n = cp - bp + 1;
						bp = cp + 1;
					}
				} else {
					if (*cp == '\n') {
#ifndef	BRIDGE
						*cp++ = '\r';
#endif
						*cp++ = '\n';
						n = cp - bp;
						bp = cp;
						nc++;
						continue;
					}

					n = cp - bp + 1;
					bp = cp + 1;
				}
			}
			else {
#ifdef	BRIDGE
				switch (n = read (fd, bp, ep - bp)) {
#else
				switch (n = read (fd, bp, ep - bp)) {
#endif
				case NOTOK:
				case OK:
					break;

				default:
					bp += n;
					continue;
				}
			}
			break;
		}
		if (n == NOTOK || (n = bp - (char *) pe -> pe_prim) == 0)
			break;
		pe -> pe_len = n;

		if (fp && !effector) {
			if ((de = pe_cpy (pe)) == NULLPE) {
				reason = FS_ACC_LCL;
				errno = ENOMEM;
				goto do_cancel;
			}
		} else
			de = pe;

		if (debug) {
			if (fp) {
				WATCHP (DOCS_FTAM__1__Datatype1, de, 0);
			} else
				WATCHP (DOCS_FTAM__3__Datatype1, de, 0);
		}

		switch (de2fadu (de, pe != de ? 1 : 0)) {
		case NOTOK:
			if (fp)
				 fclose (fp);
			return NOTOK;

		case OK:
		default:
			if (verbose || hash)
				cc += (n - nc), nc = 0;
			if (hash) {
				if (hash > 1)
					 printf ("%d\r", cc);
				else
					for (; marks < cc; marks += BUFSIZ)
						 putchar ('#');
				 fflush (stdout);
			}
			break;

		case DONE:
			 de2fadu (NULLPE, 0);
			if (fp)
				 fclose (fp);
			goto done_transfer;
		}
	}

	if (verbose)
		timer (cc, "sent");

	if (fp)
		 fclose (fp);

	if (n == NOTOK) {
		struct FTAMdiagnostic   diags[NFDIAG];
		struct FTAMdiagnostic *dp;

#ifdef	BRIDGE
		advise (dst, "error reading");
#else
		advise (src, "error reading");
#endif
		reason = FS_ACC_LCLDEV;

do_cancel:
		;
		dp = diags;

		dp -> ftd_type = DIAG_PERM;
		dp -> ftd_identifier = reason;
		dp -> ftd_observer = dp -> ftd_source = EREF_IFSU;
		dp -> ftd_delay = DIAG_NODELAY;
		 strcpy (dp -> ftd_data, sys_errname (errno));
		dp -> ftd_cc = strlen (dp -> ftd_data);
		dp++;

		 de2fadu (NULLPE, 0);

		if (FCancelRequest (ftamfd, FACTION_PERM, NULLPE, diags, dp - diags,
							fti) == NOTOK) {
			ftam_advise (fta, "F-CANCEL.REQUEST");
			return NOTOK;
		}

		if (fti -> fti_type == FTI_CANCEL) {
			struct FTAMcancel *ftcn = &fti -> fti_cancel;

			ftam_diag (ftcn -> ftcn_diags, ftcn -> ftcn_ndiag, 1,
					   ftcn -> ftcn_action);
			FTCNFREE (ftcn);
		}

		goto done_transfer;
	}

	if (n == OK)
		n = de2fadu (NULLPE, 1);

	if (FDataEndRequest (ftamfd, FACTION_SUCCESS, (struct FTAMdiagnostic *) 0,
						 0, fti) == NOTOK) {
		ftam_advise (fta, "F-DATA-END.REQUEST");
		return NOTOK;
	}

	if (FTransEndRequest (ftamfd, NULLPE, fti) == NOTOK) {
		ftam_advise (fta, "F-TRANSFER-END.REQUEST");
		return NOTOK;
	}

	switch (fti -> fti_type) {
	case FTI_TRANSEND: {
		struct FTAMtransend   *ftre = &fti -> fti_transend;

		ftam_diag (ftre -> ftre_diags, ftre -> ftre_ndiag, 1,
				   ftre -> ftre_action);
		FTREFREE (ftre);
	}
	break;

	case FTI_CANCEL: {
		struct FTAMcancel *ftcn = &fti -> fti_cancel;

		advise (NULLCP, "data transfer canceled!");
		ftam_diag (ftcn -> ftcn_diags, ftcn -> ftcn_ndiag, 1,
				   ftcn -> ftcn_action);
		FTCNFREE (ftcn);

		if (FCancelResponse (ftamfd, FACTION_SUCCESS, NULLPE,
							 (struct FTAMdiagnostic *) 0, 0, fti) == NOTOK) {
			ftam_advise (fta, "F-CANCEL.RESPONSE");
			return NOTOK;
		}
	}
	break;

	default:
		adios (NULLCP, "unexpected indication type=%d", fti -> fti_type);
	}

done_transfer:
	;
	ftg = &ftgs;
	bzero ((char *) ftg, sizeof *ftg);
	ftg -> ftg_flags |= FTG_BEGIN | FTG_END;
	ftg -> ftg_threshold = 0;

	ftg -> ftg_flags |= FTG_CLOSE;
	ftg -> ftg_threshold++;

	ftg -> ftg_flags |= FTG_DESELECT;
	ftg -> ftg_threshold++;

	if (FBulkEndRequest (ftamfd, ftg, fti) == NOTOK) {
		ftam_advise (fta, "F-BULK-END.REQUEST");
		return NOTOK;
	}

	ftg = &fti -> fti_group;

	if (ftg -> ftg_flags & FTG_CLOSE) {
		struct FTAMclose  *ftcl = &ftg -> ftg_close;

		ftam_diag (ftcl -> ftcl_diags, ftcl -> ftcl_ndiag, 1,
				   ftcl -> ftcl_action);
	}

	if (ftg -> ftg_flags & FTG_DESELECT) {
		struct FTAMdeselect   *ftde = &ftg -> ftg_deselect;

		ftam_diag (ftde -> ftde_diags, ftde -> ftde_ndiag, 1,
				   ftde -> ftde_action);
		ftam_chrg (&ftde -> ftde_charges);
	}

	FTGFREE (ftg);
	return OK;

you_lose:
	;
	FTGFREE (ftg);
	return NOTOK;
}

/*  */

int	de2fadu (pe, concat)
PE	pe;
int	concat;
{
	int	    result;
	struct FTAMindication   ftis;
	struct FTAMindication *fti = &ftis;
	struct FTAMabort  *fta = &fti -> fti_abort;
	static int ninfo = 0;
	static int size = 0;
	static PE info[NPDATA];

	if (pe == NULLPE) {
		result = OK;
		if (concat
				&& ninfo > 0
				&& FDataRequest (ftamfd, info, ninfo, fti) == NOTOK) {
			ftam_advise (fta, "F-DATA.REQUEST");
			result = NOTOK;
		}

		while (ninfo > 0)
			pe_free (info[--ninfo]);
		size = 0;

		return result;
	}

	if (concat) {
		int	flush,
			n;

		if (size + (n = ps_get_abs (pe) + MAGIC_OCTET2) >= fadusize
				&& ninfo > 0) {
			if (debug)
				advise (NULLCP,
						"de2fadu flushing on %d FADUs, estimated size %d/%d",
						ninfo, size, fadusize);

			if ((result = de2fadu (NULLPE, 1)) != OK)
				return result;
			flush = 1;
		} else
			flush = 0;

		info[ninfo++] = pe;
		size += n;

		if (ninfo < NPDATA && size < fadusize) {
			if (!flush)
				return OK;
		} else {
			if ((result = FDataRequest (ftamfd, info, ninfo, fti)) == NOTOK)
				ftam_advise (fta, "F-DATA.REQUEST");

			while (ninfo > 0)
				pe_free (info[--ninfo]);
			size = 0;

			if (result == NOTOK)
				return result;
		}
	} else if (FDataRequest (ftamfd, &pe, 1, fti) == NOTOK) {
		ftam_advise (fta, "F-DATA.REQUEST");
		return NOTOK;
	}

	if (FWaitRequest (ftamfd, OK, fti) == NOTOK) {
		if (fta -> fta_peer
				|| fta -> fta_action != FACTION_TRANS
				|| fta -> fta_ndiag < 1
				|| fta -> fta_diags[0].ftd_type != DIAG_TRANS
				|| fta -> fta_diags[0].ftd_identifier != FS_PRO_TIMEOUT) {
			ftam_advise (fta, "F-WAIT.REQUEST");
			return NOTOK;
		}

		return OK;
	}

	if (fti -> fti_type == FTI_CANCEL) {
		struct FTAMcancel *ftcn = &fti -> fti_cancel;

		advise (NULLCP, "data transfer cancelled!");
		ftam_diag (ftcn -> ftcn_diags, ftcn -> ftcn_ndiag, 1,
				   ftcn -> ftcn_action);
		FTCNFREE (ftcn);

		if (FCancelResponse (ftamfd, FACTION_SUCCESS, NULLPE,
							 (struct FTAMdiagnostic *) 0, 0, fti) == NOTOK) {
			ftam_advise (fta, "F-CANCEL.RESPONSE");
			return NOTOK;
		}
	}

	return DONE;
}
Exemple #3
0
static void
_shop_cmp_pathstate(shopping_state_s *ssp, CCS pskey, CS ptxes1)
{
    unsigned vlen;
    int ignored;
    pa_o dummy_pa;
    ps_o shopped_ps;
    CCS path, reason = NULL;
    CS csv, ptxbuf, explanation = NULL;

    if (cdb_find(ssp->cdbp, pskey, strlen(pskey)) <= 0) {
	putil_int("bad PS key in roadmap: %s", pskey);
	return;
    }

    vlen = cdb_datalen(ssp->cdbp);
    csv = (CS)alloca(vlen + 1);
    cdb_read(ssp->cdbp, csv, vlen, cdb_datapos(ssp->cdbp));
    csv[vlen] = '\0';
    shopped_ps = ps_newFromCSVString(csv);

    path = ps_get_abs(shopped_ps);

    // Figure out if this path is to be ignored per user request.
    // We may still want to do the comparison for ignored paths
    // in order to issue warnings (the user might wish to know
    // what didn't match without failing the build).
    ignored = re_match__(ssp->ignore_path_re, path) != NULL;

    if (!CurrentPS || strcmp(ps_get_abs(CurrentPS), path)) {
	ps_destroy(CurrentPS);
	CurrentPS = ps_newFromPath(path);
	if (ps_stat(CurrentPS, ps_has_dcode(shopped_ps))) {
	    asprintf(&explanation, "%s: %s", path, strerror(errno));
	}
    }

    // Do the actual comparison.
    // IDEA - choose a model here: Either we can ignore paths
    // before comparison (thus saving time) or after (allowing
    // a useful warning to be issued). Or we could add a new
    // preference allowing user choice.
    if (explanation || (reason = ps_diff(shopped_ps, CurrentPS))) {
	CS ixstr;

	// If this iteration produced a mismatch, invalidate all the
	// PTXes associated with that PS.
	if (reason) {
	    if (asprintf(&explanation, "%s mismatch on %s",
		    reason, path) < 0) {
		putil_syserr(2, NULL);
	    }
	}

	ptxbuf = (CS)alloca(strlen(ptxes1) + CHARSIZE);
	strcpy(ptxbuf, ptxes1);
	for (ixstr = util_strsep(&ptxbuf, FS2);
		 ixstr && _shop_ptx_count(ssp);
		 ixstr = util_strsep(&ptxbuf, FS2)) {
	    _shop_ptx_invalidate(ssp, ixstr, explanation, ignored);
	}

	// If the failing path is not ignored for shopping, this
	// loop iteration is finished.
	if (!ignored) {
	    ps_destroy(shopped_ps);
	    return;
	}
    }

    putil_free(explanation);

    // The current PS matched, so hold onto it. Unfortunately a
    // CA object doesn't hold PS objects, it holds PAs, so we
    // must wrap the PS in a dummy PA.
    // The only reason prereqs are saved at all is to let a
    // recycled CA generate the same signature as if it had
    // actually run.
    dummy_pa = pa_new();
    pa_set_ps(dummy_pa, ps_copy(CurrentPS));
    pa_set_op(dummy_pa, OP_READ);
    pa_set_call(dummy_pa, "dummy");
    ca_record_pa(ssp->ca, dummy_pa);

    ps_destroy(shopped_ps);
    return;
}
Exemple #4
0
void
git_store_blob(ps_o ps)
{
    CCS sha1, blob, path;
    CS blob_dir;
    int fd, ret;
    z_stream stream;
    char hdr[64];
    unsigned char cprsbuf[4096], *fdata;
    uint64_t fsize;
    struct stat64 stbuf;

    path = ps_get_abs(ps);
    sha1 = ps_get_dcode(ps);

    if ((fd = open64(path, O_RDONLY | O_BINARY)) == -1) {
	putil_syserr(2, path);
    }

    if (fstat64(fd, &stbuf)) {
	close(fd);
	putil_syserr(2, path);
    }

    fsize = stbuf.st_size;
    fdata = util_map_file(path, fd, 0, fsize);
    close(fd);

    blob = git_path_to_blob(sha1);
    if (!access(blob, F_OK)) {
	return;
    }
    if ((blob_dir = putil_dirname(blob))) {
	if (access(blob_dir, F_OK) && putil_mkdir_p(blob_dir)) {
	    putil_syserr(2, blob_dir);
	}
	putil_free(blob_dir);
    }

    if ((fd = open64(blob, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0444)) == -1) {
	putil_syserr(2, blob);
    }

    memset(&stream, 0, sizeof(stream));
    if (deflateInit(&stream, Z_BEST_SPEED) != Z_OK) {
	putil_die("unable to compress %s: %s",
	    path, stream.msg ? stream.msg : "unknown error");
    }
    stream.avail_out = sizeof(cprsbuf);
    stream.next_out = cprsbuf;

    snprintf(hdr, charlen(hdr), "blob %lu", ps_get_size(ps));
    stream.next_in = (unsigned char *)hdr;
    stream.avail_in = strlen(hdr) + 1;
    while(deflate(&stream, 0) == Z_OK);

    stream.next_in = fdata;
    stream.avail_in = (uInt)fsize;
    do {
	ret = deflate(&stream, Z_FINISH);
	if (util_write_all(fd, cprsbuf, stream.next_out - cprsbuf) < 0) {
	    putil_syserr(2, blob);
	}
	stream.avail_out = sizeof(cprsbuf);
	stream.next_out = cprsbuf;
    } while (ret == Z_OK);

    close(fd);
    util_unmap_file(fdata, fsize);
    putil_free(blob);
}