Ejemplo n.º 1
0
/**
 * Read a deb-split part archive.
 *
 * @return Part info (nfmalloc'd) if was an archive part and we read it,
 *         NULL if it wasn't.
 */
struct partinfo *read_info(FILE *partfile, const char *fn, struct partinfo *ir) {
  static char *readinfobuf= NULL;
  static size_t readinfobuflen= 0;

  size_t thisilen;
  intmax_t templong;
  char magicbuf[sizeof(DPKG_AR_MAGIC) - 1], *rip, *partnums, *slash;
  const char *err;
  struct ar_hdr arh;
  int c;
  struct stat stab;

  if (fread(magicbuf, 1, sizeof(magicbuf), partfile) != sizeof(magicbuf)) {
    if (ferror(partfile))
      ohshite(_("error reading %.250s"), fn);
    else
      return NULL;
  }
  if (memcmp(magicbuf, DPKG_AR_MAGIC, sizeof(magicbuf)))
    return NULL;

  if (fread(&arh,1,sizeof(arh),partfile) != sizeof(arh)) rerreof(partfile,fn);

  dpkg_ar_normalize_name(&arh);

  if (strncmp(arh.ar_name, PARTMAGIC, sizeof(arh.ar_name)) != 0)
    return NULL;
  if (dpkg_ar_member_is_illegal(&arh))
    ohshit(_("file `%.250s' is corrupt - bad magic at end of first header"),fn);
  thisilen = dpkg_ar_member_get_size(fn, &arh);
  if (thisilen >= readinfobuflen) {
    readinfobuflen= thisilen+1;
    readinfobuf= m_realloc(readinfobuf,readinfobuflen);
  }
  if (fread(readinfobuf,1,thisilen,partfile) != thisilen) rerreof(partfile,fn);
  if (thisilen & 1) {
    c= getc(partfile);  if (c==EOF) rerreof(partfile,fn);
    if (c != '\n')
      ohshit(_("file `%.250s' is corrupt - bad padding character (code %d)"),fn,c);
  }
  readinfobuf[thisilen] = '\0';
  if (memchr(readinfobuf,0,thisilen))
    ohshit(_("file `%.250s' is corrupt - nulls in info section"),fn);

  ir->filename= fn;

  rip= readinfobuf;
  err = deb_version_parse(&ir->fmtversion,
                          nextline(&rip, fn, _("format version number")));
  if (err)
    ohshit(_("file '%.250s' has invalid format version: %s"), fn, err);
  if (ir->fmtversion.major != 2)
    ohshit(_("file '%.250s' is format version %d.%d; get a newer dpkg-split"),
           fn, ir->fmtversion.major, ir->fmtversion.minor);

  ir->package = nfstrsave(nextline(&rip, fn, _("package name")));
  ir->version = nfstrsave(nextline(&rip, fn, _("package version number")));
  ir->md5sum = nfstrsave(nextline(&rip, fn, _("package file MD5 checksum")));
  if (strlen(ir->md5sum) != MD5HASHLEN ||
      strspn(ir->md5sum, "0123456789abcdef") != MD5HASHLEN)
    ohshit(_("file `%.250s' is corrupt - bad MD5 checksum `%.250s'"),fn,ir->md5sum);

  ir->orglength = parse_intmax(nextline(&rip, fn, _("archive total size")),
                               fn, _("archive total size"));
  ir->maxpartlen = parse_intmax(nextline(&rip, fn, _("archive part offset")),
                                fn, _("archive part offset"));

  partnums = nextline(&rip, fn, _("archive part numbers"));
  slash= strchr(partnums,'/');
  if (!slash)
    ohshit(_("file '%.250s' is corrupt - no slash between archive part numbers"), fn);
  *slash++ = '\0';

  templong = parse_intmax(slash, fn, _("number of archive parts"));
  if (templong <= 0 || templong > INT_MAX)
    ohshit(_("file '%.250s' is corrupt - bad number of archive parts"), fn);
  ir->maxpartn= templong;
  templong = parse_intmax(partnums, fn, _("archive parts number"));
  if (templong <= 0 || templong > ir->maxpartn)
    ohshit(_("file '%.250s' is corrupt - bad archive part number"),fn);
  ir->thispartn= templong;

  /* If the package was created with dpkg 1.16.1 or later it will include
   * the architecture. */
  if (*rip != '\0')
    ir->arch = nfstrsave(nextline(&rip, fn, _("package architecture")));
  else
    ir->arch = NULL;

  if (fread(&arh,1,sizeof(arh),partfile) != sizeof(arh)) rerreof(partfile,fn);

  dpkg_ar_normalize_name(&arh);

  if (dpkg_ar_member_is_illegal(&arh))
    ohshit(_("file `%.250s' is corrupt - bad magic at end of second header"),fn);
  if (strncmp(arh.ar_name,"data",4))
    ohshit(_("file `%.250s' is corrupt - second member is not data member"),fn);

  ir->thispartlen = dpkg_ar_member_get_size(fn, &arh);
  ir->thispartoffset= (ir->thispartn-1)*ir->maxpartlen;

  if (ir->maxpartn != (ir->orglength+ir->maxpartlen-1)/ir->maxpartlen)
    ohshit(_("file `%.250s' is corrupt - wrong number of parts for quoted sizes"),fn);
  if (ir->thispartlen !=
      (ir->thispartn == ir->maxpartn
       ? ir->orglength - ir->thispartoffset : ir->maxpartlen))
    ohshit(_("file `%.250s' is corrupt - size is wrong for quoted part number"),fn);

  ir->filesize = (strlen(DPKG_AR_MAGIC) +
                  sizeof(arh) + thisilen + (thisilen & 1) +
                  sizeof(arh) + ir->thispartlen + (ir->thispartlen & 1));

  if (fstat(fileno(partfile),&stab)) ohshite(_("unable to fstat part file `%.250s'"),fn);
  if (S_ISREG(stab.st_mode)) {
    /* Don't do this check if it's coming from a pipe or something.  It's
     * only an extra sanity check anyway. */
    if (stab.st_size < ir->filesize)
      ohshit(_("file `%.250s' is corrupt - too short"),fn);
  }

  ir->headerlen = strlen(DPKG_AR_MAGIC) +
                  sizeof(arh) + thisilen + (thisilen & 1) + sizeof(arh);

  return ir;
}
Ejemplo n.º 2
0
void do_auto(const char *const *argv) {
    const char *partfile;
    struct partinfo *pi, *refi, *npi, **partlist, *otherthispart;
    struct partqueue *pq;
    unsigned int i;
    int j, ap;
    long nr;
    FILE *part;
    void *buffer;
    char *p, *q;

    if (!opt_outputfile)
        badusage(_("--auto requires the use of the --output option"));
    if (!(partfile= *argv++) || *argv)
        badusage(_("--auto requires exactly one part file argument"));

    refi= nfmalloc(sizeof(struct partqueue));
    part= fopen(partfile,"r");
    if (!part) ohshite(_("unable to read part file `%.250s'"),partfile);
    if (!read_info(part,partfile,refi)) {
        if (!opt_npquiet)
            printf(_("File `%.250s' is not part of a multipart archive.\n"),partfile);
        m_output(stdout, _("<standard output>"));
        exit(1);
    }
    fclose(part);
    scandepot();
    partlist= nfmalloc(sizeof(struct partinfo*)*refi->maxpartn);
    for (i = 0; i < refi->maxpartn; i++)
        partlist[i] = NULL;
    for (pq= queue; pq; pq= pq->nextinqueue) {
        pi= &pq->info;
        if (!partmatches(pi,refi)) continue;
        npi= nfmalloc(sizeof(struct partinfo));
        mustgetpartinfo(pi->filename,npi);
        addtopartlist(partlist,npi,refi);
    }
    /* If we already have a copy of this version we ignore it and prefer the
     * new one, but we still want to delete the one in the depot, so we
     * save its partinfo (with the filename) for later. This also prevents
     * us from accidentally deleting the source file. */
    otherthispart= partlist[refi->thispartn-1];
    partlist[refi->thispartn-1]= refi;
    for (j=refi->maxpartn-1; j>=0 && partlist[j]; j--);

    if (j>=0) {

        part= fopen(partfile,"r");
        if (!part) ohshite(_("unable to reopen part file `%.250s'"),partfile);
        buffer= nfmalloc(refi->filesize);
        nr= fread(buffer,1,refi->filesize,part);
        if (nr != refi->filesize) rerreof(part,partfile);
        if (getc(part) != EOF) ohshit(_("part file `%.250s' has trailing garbage"),partfile);
        if (ferror(part)) rerr(partfile);
        fclose(part);
        p = nfmalloc(strlen(opt_depotdir) + 50);
        q = nfmalloc(strlen(opt_depotdir) + 200);
        sprintf(p, "%st.%lx", opt_depotdir, (long)getpid());
        sprintf(q, "%s%s.%lx.%x.%x", opt_depotdir, refi->md5sum,
                refi->maxpartlen,refi->thispartn,refi->maxpartn);
        part= fopen(p,"w");
        if (!part) ohshite(_("unable to open new depot file `%.250s'"),p);
        nr= fwrite(buffer,1,refi->filesize,part);
        if (nr != refi->filesize) werr(p);
        if (fflush(part))
            ohshite(_("unable to flush file '%s'"), p);
        if (fsync(fileno(part)))
            ohshite(_("unable to sync file '%s'"), p);
        if (fclose(part)) werr(p);
        if (rename(p,q)) ohshite(_("unable to rename new depot file `%.250s' to `%.250s'"),p,q);

        printf(_("Part %d of package %s filed (still want "),refi->thispartn,refi->package);
        /* There are still some parts missing. */
        for (i=0, ap=0; i<refi->maxpartn; i++)
            if (!partlist[i])
                printf("%s%d", !ap++ ? "" : i == (unsigned int)j ? _(" and ") : ", ", i + 1);
        printf(").\n");

        dir_sync_path(opt_depotdir);
    } else {

        /* We have all the parts. */
        reassemble(partlist, opt_outputfile);

        /* OK, delete all the parts (except the new one, which we never copied). */
        partlist[refi->thispartn-1]= otherthispart;
        for (i=0; i<refi->maxpartn; i++)
            if (partlist[i])
                if (unlink(partlist[i]->filename))
                    ohshite(_("unable to delete used-up depot file `%.250s'"),partlist[i]->filename);

    }

    m_output(stderr, _("<standard error>"));
}