コード例 #1
0
ファイル: t-varbuf.c プロジェクト: samdunne/dpkg-diversions
static void
test_varbuf_grow(void)
{
	struct varbuf vb;
	size_t old_size;
	int i;

	varbuf_init(&vb, 10);

	/* Test that we grow when needed. */
	varbuf_grow(&vb, 100);
	test_pass(vb.used == 0);
	test_pass(vb.size >= 100);

	old_size = vb.size;

	/* Test that we are not leaking. */
	for (i = 0; i < 10; i++) {
		varbuf_grow(&vb, 100);
		test_pass(vb.used == 0);
		test_pass(vb.size >= 100);
		test_pass(vb.size == old_size);
	}

	/* Test that we grow when needed, with used space. */
	vb.used = 10;
	varbuf_grow(&vb, 100);
	test_pass(vb.used == 10);
	test_pass(vb.size >= 110);

	varbuf_destroy(&vb);
}
コード例 #2
0
ファイル: varbuf.c プロジェクト: guillemj/dpkg
void
varbuf_add_buf(struct varbuf *v, const void *s, size_t size)
{
  varbuf_grow(v, size);
  memcpy(v->buf + v->used, s, size);
  v->used += size;
}
コード例 #3
0
ファイル: varbuf.c プロジェクト: guillemj/dpkg
void
varbuf_dup_char(struct varbuf *v, int c, size_t n)
{
  varbuf_grow(v, n);
  memset(v->buf + v->used, c, n);
  v->used += n;
}
コード例 #4
0
ファイル: build.c プロジェクト: nisc-code/dpkg
/**
 * Read a filename from the file descriptor and create a file_info struct.
 *
 * @return A file_info struct or NULL if there is nothing to read.
 */
static struct file_info *
file_info_get(const char *root, int fd)
{
  static struct varbuf fn = VARBUF_INIT;
  struct file_info *fi;
  size_t root_len;

  varbuf_reset(&fn);
  root_len = varbuf_printf(&fn, "%s/", root);

  while (1) {
    int res;

    varbuf_grow(&fn, 1);
    res = fd_read(fd, (fn.buf + fn.used), 1);
    if (res < 0)
      return NULL;
    if (res == 0) /* EOF -> parent died. */
      return NULL;
    if (fn.buf[fn.used] == '\0')
      break;

    varbuf_trunc(&fn, fn.used + 1);
    if (fn.used >= MAXFILENAME)
      ohshit(_("file name '%.50s...' is too long"), fn.buf + root_len);
  }

  fi = file_info_new(fn.buf + root_len);
  if (lstat(fn.buf, &(fi->st)) != 0)
    ohshite(_("unable to stat file name '%.250s'"), fn.buf);

  return fi;
}
コード例 #5
0
ファイル: varbuf.c プロジェクト: guillemj/dpkg
int
varbuf_vprintf(struct varbuf *v, const char *fmt, va_list args)
{
  va_list args_copy;
  int needed, r;

  va_copy(args_copy, args);
  needed = vsnprintf(NULL, 0, fmt, args_copy);
  va_end(args_copy);

  if (needed < 0)
    ohshite(_("error formatting string into varbuf variable"));

  varbuf_grow(v, needed + 1);

  r = vsnprintf(v->buf + v->used, needed + 1, fmt, args);
  if (r < 0)
    ohshite(_("error formatting string into varbuf variable"));

  v->used += r;

  return r;
}
コード例 #6
0
ファイル: varbuf.c プロジェクト: guillemj/dpkg
void
varbuf_add_char(struct varbuf *v, int c)
{
  varbuf_grow(v, 1);
  v->buf[v->used++]= c;
}
コード例 #7
0
ファイル: varbuf.c プロジェクト: guillemj/dpkg
void
varbuf_end_str(struct varbuf *v)
{
  varbuf_grow(v, 1);
  v->buf[v->used] = '\0';
}
コード例 #8
0
ファイル: archives.c プロジェクト: Minipig/dpkg
int
tarobject(void *ctx, struct tar_entry *ti)
{
  static struct varbuf conffderefn, hardlinkfn, symlinkfn;
  static int fd;
  const char *usename;
  struct filenamenode *usenode;
  struct filenamenode *linknode;

  struct conffile *conff;
  struct tarcontext *tc = ctx;
  bool existingdirectory, keepexisting;
  int statr;
  ssize_t r;
  struct stat stab, stabtmp;
  char databuf[TARBLKSZ];
  struct file_stat *st;
  struct fileinlist *nifd, **oldnifd;
  struct pkginfo *divpkg, *otherpkg;

  ensureobstackinit();

  /* Append to list of files.
   * The trailing ‘/’ put on the end of names in tarfiles has already
   * been stripped by tar_extractor(). */
  oldnifd= tc->newfilesp;
  nifd= addfiletolist(tc, findnamenode(ti->name, 0));
  nifd->namenode->flags |= fnnf_new_inarchive;

  debug(dbg_eachfile,
        "tarobject ti->name='%s' mode=%lo owner=%u.%u type=%d(%c)"
        " ti->linkname='%s' namenode='%s' flags=%o instead='%s'",
        ti->name, (long)ti->stat.mode,
        (unsigned)ti->stat.uid, (unsigned)ti->stat.gid,
        ti->type,
        ti->type >= '0' && ti->type <= '6' ? "-hlcbdp"[ti->type - '0'] : '?',
        ti->linkname,
        nifd->namenode->name, nifd->namenode->flags,
        nifd->namenode->divert && nifd->namenode->divert->useinstead
        ? nifd->namenode->divert->useinstead->name : "<none>");

  if (nifd->namenode->divert && nifd->namenode->divert->camefrom) {
    divpkg= nifd->namenode->divert->pkg;

    if (divpkg) {
      forcibleerr(fc_overwritediverted,
                  _("trying to overwrite `%.250s', which is the "
                    "diverted version of `%.250s' (package: %.100s)"),
                  nifd->namenode->name, nifd->namenode->divert->camefrom->name,
                  divpkg->name);
    } else {
      forcibleerr(fc_overwritediverted,
                  _("trying to overwrite `%.250s', which is the "
                    "diverted version of `%.250s'"),
                  nifd->namenode->name, nifd->namenode->divert->camefrom->name);
    }
  }

  if (nifd->namenode->statoverride)
    st = nifd->namenode->statoverride;
  else
    st = &ti->stat;

  usenode = namenodetouse(nifd->namenode, tc->pkg);
  usename = usenode->name + 1; /* Skip the leading '/'. */

  trig_file_activate(usenode, tc->pkg);

  if (nifd->namenode->flags & fnnf_new_conff) {
    /* If it's a conffile we have to extract it next to the installed
     * version (i.e. we do the usual link-following). */
    if (conffderef(tc->pkg, &conffderefn, usename))
      usename= conffderefn.buf;
    debug(dbg_conff,"tarobject fnnf_new_conff deref=`%s'",usename);
  }

  setupfnamevbs(usename);

  statr= lstat(fnamevb.buf,&stab);
  if (statr) {
    /* The lstat failed. */
    if (errno != ENOENT && errno != ENOTDIR)
      ohshite(_("unable to stat `%.255s' (which I was about to install)"),
              ti->name);
    /* OK, so it doesn't exist.
     * However, it's possible that we were in the middle of some other
     * backup/restore operation and were rudely interrupted.
     * So, we see if we have .dpkg-tmp, and if so we restore it. */
    if (rename(fnametmpvb.buf,fnamevb.buf)) {
      if (errno != ENOENT && errno != ENOTDIR)
        ohshite(_("unable to clean up mess surrounding `%.255s' before "
                  "installing another version"), ti->name);
      debug(dbg_eachfiledetail,"tarobject nonexistent");
    } else {
      debug(dbg_eachfiledetail,"tarobject restored tmp to main");
      statr= lstat(fnamevb.buf,&stab);
      if (statr) ohshite(_("unable to stat restored `%.255s' before installing"
                           " another version"), ti->name);
    }
  } else {
    debug(dbg_eachfiledetail,"tarobject already exists");
  }

  /* Check to see if it's a directory or link to one and we don't need to
   * do anything. This has to be done now so that we don't die due to
   * a file overwriting conflict. */
  existingdirectory = false;
  switch (ti->type) {
  case tar_filetype_symlink:
    /* If it's already an existing directory, do nothing. */
    if (!statr && S_ISDIR(stab.st_mode)) {
      debug(dbg_eachfiledetail, "tarobject symlink exists as directory");
      existingdirectory = true;
    } else if (!statr && S_ISLNK(stab.st_mode)) {
      if (linktosameexistingdir(ti, fnamevb.buf, &symlinkfn))
        existingdirectory = true;
    }
    break;
  case tar_filetype_dir:
    /* If it's already an existing directory, do nothing. */
    if (!stat(fnamevb.buf,&stabtmp) && S_ISDIR(stabtmp.st_mode)) {
      debug(dbg_eachfiledetail, "tarobject directory exists");
      existingdirectory = true;
    }
    break;
  case tar_filetype_file:
  case tar_filetype_chardev:
  case tar_filetype_blockdev:
  case tar_filetype_fifo:
  case tar_filetype_hardlink:
    break;
  default:
    ohshit(_("archive contained object `%.255s' of unknown type 0x%x"),
           ti->name, ti->type);
  }

  keepexisting = false;
  if (!existingdirectory) {
    struct filepackages_iterator *iter;

    iter = filepackages_iter_new(nifd->namenode);
    while ((otherpkg = filepackages_iter_next(iter))) {
      if (otherpkg == tc->pkg)
        continue;
      debug(dbg_eachfile, "tarobject ... found in %s", otherpkg->name);

      if (nifd->namenode->divert && nifd->namenode->divert->useinstead) {
        /* Right, so we may be diverting this file. This makes the conflict
         * OK iff one of us is the diverting package (we don't need to
         * check for both being the diverting package, obviously). */
        divpkg = nifd->namenode->divert->pkg;
        debug(dbg_eachfile, "tarobject ... diverted, divpkg=%s",
              divpkg ? divpkg->name : "<none>");
        if (otherpkg == divpkg || tc->pkg == divpkg)
          continue;
      }

      /* Nope? Hmm, file conflict, perhaps. Check Replaces. */
      switch (otherpkg->clientdata->replacingfilesandsaid) {
      case 2:
        keepexisting = true;
      case 1:
        continue;
      }

      /* Is the package with the conflicting file in the “config files only”
       * state? If so it must be a config file and we can silenty take it
       * over. */
      if (otherpkg->status == stat_configfiles)
        continue;

      /* Perhaps we're removing a conflicting package? */
      if (otherpkg->clientdata->istobe == itb_remove)
        continue;

      /* Is the file an obsolete conffile in the other package
       * and a conffile in the new package? */
      if ((nifd->namenode->flags & fnnf_new_conff) &&
          !statr && S_ISREG(stab.st_mode)) {
        for (conff = otherpkg->installed.conffiles;
             conff;
             conff = conff->next) {
          if (!conff->obsolete)
            continue;
          if (stat(conff->name, &stabtmp))
            if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP)
              continue;
            if (stabtmp.st_dev == stab.st_dev &&
                stabtmp.st_ino == stab.st_ino)
              break;
        }
        if (conff) {
          debug(dbg_eachfiledetail, "tarobject other's obsolete conffile");
          /* process_archive() will have copied its hash already. */
          continue;
        }
      }

      if (does_replace(tc->pkg, &tc->pkg->available,
                       otherpkg, &otherpkg->installed)) {
        printf(_("Replacing files in old package %s ...\n"),otherpkg->name);
        otherpkg->clientdata->replacingfilesandsaid = 1;
      } else if (does_replace(otherpkg, &otherpkg->installed,
                              tc->pkg, &tc->pkg->available)) {
        printf(_("Replaced by files in installed package %s ...\n"),
               otherpkg->name);
        otherpkg->clientdata->replacingfilesandsaid = 2;
        nifd->namenode->flags &= ~fnnf_new_inarchive;
        keepexisting = true;
      } else {
        if (!statr && S_ISDIR(stab.st_mode)) {
          forcibleerr(fc_overwritedir,
                      _("trying to overwrite directory '%.250s' "
                        "in package %.250s %.250s with nondirectory"),
                      nifd->namenode->name, otherpkg->name,
                      versiondescribe(&otherpkg->installed.version,
                                      vdew_nonambig));
        } else {
          /* At this point we are replacing something without a Replaces.
           * If the new object is a directory and the previous object does
           * not exist assume it's also a directory and don't complain. */
          if (!(statr && ti->type == tar_filetype_dir))
            forcibleerr(fc_overwrite,
                        _("trying to overwrite '%.250s', "
                          "which is also in package %.250s %.250s"),
                        nifd->namenode->name, otherpkg->name,
                        versiondescribe(&otherpkg->installed.version,
                                        vdew_nonambig));
        }
      }
    }
    filepackages_iter_free(iter);
  }

  if (keepexisting) {
    remove_file_from_list(tc, ti, oldnifd, nifd);
    tarfile_skip_one_forward(tc, ti);
    return 0;
  }

  if (filter_should_skip(ti)) {
    nifd->namenode->flags &= ~fnnf_new_inarchive;
    nifd->namenode->flags |= fnnf_filtered;
    tarfile_skip_one_forward(tc, ti);

    return 0;
  }

  if (existingdirectory)
    return 0;

  /* Now, at this stage we want to make sure neither of .dpkg-new and
   * .dpkg-tmp are hanging around. */
  ensure_pathname_nonexisting(fnamenewvb.buf);
  ensure_pathname_nonexisting(fnametmpvb.buf);

  /* Now we start to do things that we need to be able to undo
   * if something goes wrong. Watch out for the CLEANUP comments to
   * keep an eye on what's installed on the disk at each point. */
  push_cleanup(cu_installnew, ~ehflag_normaltidy, NULL, 0, 1, (void *)nifd);

  /*
   * CLEANUP: Now we either have the old file on the disk, or not, in
   * its original filename.
   */

  /* Extract whatever it is as .dpkg-new ... */
  switch (ti->type) {
  case tar_filetype_file:
    /* We create the file with mode 0 to make sure nobody can do anything with
     * it until we apply the proper mode, which might be a statoverride. */
    fd= open(fnamenewvb.buf, (O_CREAT|O_EXCL|O_WRONLY), 0);
    if (fd < 0)
      ohshite(_("unable to create `%.255s' (while processing `%.255s')"),
              fnamenewvb.buf, ti->name);
    push_cleanup(cu_closefd, ehflag_bombout, NULL, 0, 1, &fd);
    debug(dbg_eachfiledetail, "tarobject file open size=%lu",
          (unsigned long)ti->size);
    { char fnamebuf[256];
    fd_fd_copy(tc->backendpipe, fd, ti->size,
               _("backend dpkg-deb during `%.255s'"),
               path_quote_filename(fnamebuf, ti->name, 256));
    }
    r = ti->size % TARBLKSZ;
    if (r > 0)
      if (safe_read(tc->backendpipe, databuf, TARBLKSZ - r) == -1)
        ohshite(_("error reading from dpkg-deb pipe"));

    fd_writeback_init(fd);

    if (nifd->namenode->statoverride)
      debug(dbg_eachfile, "tarobject ... stat override, uid=%d, gid=%d, mode=%04o",
			  nifd->namenode->statoverride->uid,
			  nifd->namenode->statoverride->gid,
			  nifd->namenode->statoverride->mode);
    if (fchown(fd, st->uid, st->gid))
      ohshite(_("error setting ownership of `%.255s'"), ti->name);
    if (fchmod(fd, st->mode & ~S_IFMT))
      ohshite(_("error setting permissions of `%.255s'"), ti->name);

    /* Postpone the fsync, to try to avoid massive I/O degradation. */
    if (!fc_unsafe_io)
      nifd->namenode->flags |= fnnf_deferred_fsync;

    pop_cleanup(ehflag_normaltidy); /* fd = open(fnamenewvb.buf) */
    if (close(fd))
      ohshite(_("error closing/writing `%.255s'"), ti->name);
    newtarobject_utime(fnamenewvb.buf, st);
    break;
  case tar_filetype_fifo:
    if (mkfifo(fnamenewvb.buf,0))
      ohshite(_("error creating pipe `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject fifo");
    newtarobject_allmodes(fnamenewvb.buf, st);
    break;
  case tar_filetype_chardev:
    if (mknod(fnamenewvb.buf, S_IFCHR, ti->dev))
      ohshite(_("error creating device `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject chardev");
    newtarobject_allmodes(fnamenewvb.buf, st);
    break;
  case tar_filetype_blockdev:
    if (mknod(fnamenewvb.buf, S_IFBLK, ti->dev))
      ohshite(_("error creating device `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject blockdev");
    newtarobject_allmodes(fnamenewvb.buf, st);
    break;
  case tar_filetype_hardlink:
    varbufreset(&hardlinkfn);
    varbufaddstr(&hardlinkfn,instdir); varbufaddc(&hardlinkfn,'/');
    varbufaddstr(&hardlinkfn, ti->linkname);
    linknode = findnamenode(ti->linkname, 0);
    if (linknode->flags & fnnf_deferred_rename)
      varbufaddstr(&hardlinkfn, DPKGNEWEXT);
    varbufaddc(&hardlinkfn, '\0');
    if (link(hardlinkfn.buf,fnamenewvb.buf))
      ohshite(_("error creating hard link `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject hardlink");
    newtarobject_allmodes(fnamenewvb.buf, st);
    break;
  case tar_filetype_symlink:
    /* We've already cheched for an existing directory. */
    if (symlink(ti->linkname, fnamenewvb.buf))
      ohshite(_("error creating symbolic link `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject symlink creating");
    if (lchown(fnamenewvb.buf, st->uid, st->gid))
      ohshite(_("error setting ownership of symlink `%.255s'"), ti->name);
    break;
  case tar_filetype_dir:
    /* We've already checked for an existing directory. */
    if (mkdir(fnamenewvb.buf,0))
      ohshite(_("error creating directory `%.255s'"), ti->name);
    debug(dbg_eachfiledetail, "tarobject directory creating");
    newtarobject_allmodes(fnamenewvb.buf, st);
    break;
  default:
    internerr("unknown tar type '%d', but already checked", ti->type);
  }

  set_selinux_path_context(fnamevb.buf, fnamenewvb.buf, st->mode);

  /*
   * CLEANUP: Now we have extracted the new object in .dpkg-new (or,
   * if the file already exists as a directory and we were trying to
   * extract a directory or symlink, we returned earlier, so we don't
   * need to worry about that here).
   *
   * The old file is still in the original filename,
   */

  /* First, check to see if it's a conffile. If so we don't install
   * it now - we leave it in .dpkg-new for --configure to take care of. */
  if (nifd->namenode->flags & fnnf_new_conff) {
    debug(dbg_conffdetail,"tarobject conffile extracted");
    nifd->namenode->flags |= fnnf_elide_other_lists;
    return 0;
  }

  /* Now we move the old file out of the way, the backup file will
   * be deleted later. */
  if (statr) {
    /* Don't try to back it up if it didn't exist. */
    debug(dbg_eachfiledetail,"tarobject new - no backup");
  } else {
    if (ti->type == tar_filetype_dir || S_ISDIR(stab.st_mode)) {
      /* One of the two is a directory - can't do atomic install. */
      debug(dbg_eachfiledetail,"tarobject directory, nonatomic");
      nifd->namenode->flags |= fnnf_no_atomic_overwrite;
      if (rename(fnamevb.buf,fnametmpvb.buf))
        ohshite(_("unable to move aside `%.255s' to install new version"),
                ti->name);
    } else if (S_ISLNK(stab.st_mode)) {
      /* We can't make a symlink with two hardlinks, so we'll have to
       * copy it. (Pretend that making a copy of a symlink is the same
       * as linking to it.) */
      varbufreset(&symlinkfn);
      varbuf_grow(&symlinkfn, stab.st_size + 1);
      r = readlink(fnamevb.buf, symlinkfn.buf, symlinkfn.size);
      if (r < 0)
        ohshite(_("unable to read link `%.255s'"), ti->name);
      assert(r == stab.st_size);
      varbuf_trunc(&symlinkfn, r);
      varbufaddc(&symlinkfn, '\0');
      if (symlink(symlinkfn.buf,fnametmpvb.buf))
        ohshite(_("unable to make backup symlink for `%.255s'"), ti->name);
      if (lchown(fnametmpvb.buf,stab.st_uid,stab.st_gid))
        ohshite(_("unable to chown backup symlink for `%.255s'"), ti->name);
      set_selinux_path_context(fnamevb.buf, fnametmpvb.buf, stab.st_mode);
    } else {
      debug(dbg_eachfiledetail,"tarobject nondirectory, `link' backup");
      if (link(fnamevb.buf,fnametmpvb.buf))
        ohshite(_("unable to make backup link of `%.255s' before installing new version"),
                ti->name);
    }
  }

  /*
   * CLEANUP: Now the old file is in .dpkg-tmp, and the new file is still
   * in .dpkg-new.
   */

  if (ti->type == tar_filetype_file || ti->type == tar_filetype_symlink) {
    nifd->namenode->flags |= fnnf_deferred_rename;

    debug(dbg_eachfiledetail, "tarobject done and installation deferred");
  } else {
    if (rename(fnamenewvb.buf, fnamevb.buf))
      ohshite(_("unable to install new version of `%.255s'"), ti->name);

    /*
     * CLEANUP: Now the new file is in the destination file, and the
     * old file is in .dpkg-tmp to be cleaned up later. We now need
     * to take a different attitude to cleanup, because we need to
     * remove the new file.
     */

    nifd->namenode->flags |= fnnf_placed_on_disk;
    nifd->namenode->flags |= fnnf_elide_other_lists;

    debug(dbg_eachfiledetail, "tarobject done and installed");
  }

  return 0;
}