Example #1
0
static int
write_or_append (guestfs_h *g, const char *path,
                 const char *content, size_t size,
                 int append)
{
  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
  int fd = -1;
  int64_t filesize;

  /* If the content is small enough, use guestfs_internal_write{,_append}
   * since that call is more efficient.
   */
  if (size <= 2*1024*1024)
    return
      (!append ? guestfs_internal_write : guestfs_internal_write_append)
      (g, path, content, size);

  if (guestfs_int_lazy_make_tmpdir (g) == -1)
    goto err;

  /* Write the content out to a temporary file. */
  tmpfile = safe_asprintf (g, "%s/write%d", g->tmpdir, ++g->unique);

  fd = open (tmpfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600);
  if (fd == -1) {
    perrorf (g, "open: %s", tmpfile);
    goto err;
  }

  if (full_write (fd, content, size) != size) {
    perrorf (g, "write: %s", tmpfile);
    goto err;
  }

  if (close (fd) == -1) {
    perrorf (g, "close: %s", tmpfile);
    goto err;
  }
  fd = -1;

  if (!append) {
    if (guestfs_upload (g, tmpfile, path) == -1)
      goto err;
  }
  else {
    /* XXX Should have an 'upload-append' call to make this atomic. */
    filesize = guestfs_filesize (g, path);
    if (filesize == -1)
      goto err;
    if (guestfs_upload_offset (g, tmpfile, path, filesize) == -1)
      goto err;
  }

  return 0;

 err:
  if (fd >= 0)
    close (fd);
  return -1;
}
Example #2
0
int
run_hexedit (const char *cmd, size_t argc, char *argv[])
{
  if (argc < 1 || argc > 3) {
    fprintf (stderr, _("hexedit (device|filename) [max | start max]\n"));
    return -1;
  }

  const char *filename = argv[0];
  off_t size = get_size (filename);
  if (size == -1)
    return -1;

  if (size == 0) {
    fprintf (stderr,
             _("hexedit: %s is a zero length file or device\n"), filename);
    return -1;
  }

  off_t start;
  off_t max;

  if (argc == 1) {              /* hexedit device */
    /* Check we're not going to download a huge file. */
    if (size > MAX_DOWNLOAD_SIZE) {
      fprintf (stderr,
         _("hexedit: %s is larger than %s. You must supply a limit using\n"
           "  'hexedit %s <max>' (eg. 'hexedit %s 1M') or a range using\n"
           "  'hexedit %s <start> <max>'.\n"),
               filename, MAX_DOWNLOAD_SIZE_TEXT,
               filename, filename,
               filename);
      return -1;
    }

    start = 0;
    max = size;
  }
  else {
    if (argc == 3) {            /* hexedit device start max */
      if (parse_size (argv[1], &start) == -1)
        return -1;
      if (parse_size (argv[2], &max) == -1)
        return -1;
    } else {                    /* hexedit device max */
      start = 0;
      if (parse_size (argv[1], &max) == -1)
        return -1;
    }

    if (start + max > size)
      max = size - start;
  }

  if (max <= 0) {
    fprintf (stderr, _("hexedit: invalid range\n"));
    return -1;
  }

  /* Download the requested range from the remote file|device into a
   * local temporary file.
   */
  const char *editor;
  int r;
  struct stat oldstat, newstat;
  char tmpfd[sizeof "/dev/fd/" + 3 * sizeof (int)];
  CLEANUP_FREE char *editcmd = NULL;

  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g), *tmp = NULL;
  if (asprintf (&tmp, "%s/guestfishXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return -1;
  }

  int fd = mkstemp (tmp);
  if (fd == -1) {
    perror ("mkstemp");
    return -1;
  }

  /* Choose an editor. */
  editor = getenv ("HEXEDITOR");
  if (editor == NULL)
    editor = "hexedit";

  snprintf (tmpfd, sizeof tmpfd, "/dev/fd/%d", fd);

  if (guestfs_download_offset (g, filename, tmpfd, start, max) == -1) {
    unlink (tmp);
    close (fd);
    return -1;
  }

  if (close (fd) == -1) {
    unlink (tmp);
    return -1;
  }

  /* Get the old stat. */
  if (stat (tmp, &oldstat) == -1) {
    perror (tmp);
    unlink (tmp);
    return -1;
  }

  /* Edit it. */
  if (asprintf (&editcmd, "%s %s", editor, tmp) == -1) {
    perror ("asprintf");
    return -1;
  }

  r = system (editcmd);
  if (r != 0) {
    perror (editcmd);
    unlink (tmp);
    return -1;
  }

  /* Get the new stat. */
  if (stat (tmp, &newstat) == -1) {
    perror (tmp);
    unlink (tmp);
    return -1;
  }

  /* Changed? */
  if (oldstat.st_ctime == newstat.st_ctime &&
      oldstat.st_size == newstat.st_size) {
    unlink (tmp);
    return 0;
  }

  /* Write new content. */
  if (guestfs_upload_offset (g, tmp, filename, start) == -1) {
    unlink (tmp);
    return -1;
  }

  unlink (tmp);
  return 0;
}