Exemplo n.º 1
0
/* Extract the information from the entry, serialize and send it out.
 * Return 0 on success, -1 on error.
 */
static int
send_dirent_info (TSK_FS_FILE *fsfile, const char *path)
{
  XDR xdr;
  int ret = 0;
  size_t len = 0;
  struct guestfs_int_tsk_dirent dirent;
  CLEANUP_FREE char *buf = NULL, *fname = NULL;

  /* Set dirent fields */
  memset (&dirent, 0, sizeof dirent);

  /* Build the full relative path of the entry */
  ret = asprintf (&fname, "%s%s", path, fsfile->name->name);
  if (ret < 0) {
    perror ("asprintf");
    return -1;
  }

  dirent.tsk_inode = fsfile->name->meta_addr;
  dirent.tsk_type = file_type (fsfile);
  dirent.tsk_name = fname;
  dirent.tsk_flags = file_flags (fsfile);

  file_metadata (fsfile->meta, &dirent);

  /* Serialize tsk_dirent struct. */
  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
  if (buf == NULL) {
    perror ("malloc");
    return -1;
  }

  xdrmem_create (&xdr, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);

  ret = xdr_guestfs_int_tsk_dirent (&xdr, &dirent);
  if (ret == 0) {
    perror ("xdr_guestfs_int_tsk_dirent");
    return -1;
  }

  len = xdr_getpos (&xdr);

  xdr_destroy (&xdr);

  /* Send serialised tsk_dirent out. */
  return send_file_write (buf, len);
}
Exemplo n.º 2
0
/* Has one FileOut parameter. */
int
do_find0 (const char *dir)
{
  struct stat statbuf;
  int r;
  FILE *fp;
  char *cmd;
  char *sysrootdir;
  size_t sysrootdirlen, len;
  char str[GUESTFS_MAX_CHUNK_SIZE];

  sysrootdir = sysroot_path (dir);
  if (!sysrootdir) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = stat (sysrootdir, &statbuf);
  if (r == -1) {
    reply_with_perror ("%s", dir);
    free (sysrootdir);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    free (sysrootdir);
    return -1;
  }

  sysrootdirlen = strlen (sysrootdir);

  if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
    reply_with_perror ("asprintf");
    free (sysrootdir);
    return -1;
  }
  free (sysrootdir);

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    free (cmd);
    return -1;
  }
  free (cmd);

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = input_to_nul (fp, str, GUESTFS_MAX_CHUNK_SIZE)) > 0) {
    len = strlen (str);
    if (len <= sysrootdirlen)
      continue;

    /* Remove the directory part of the path before sending it. */
    if (send_file_write (str + sysrootdirlen, r - sysrootdirlen) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    perror (dir);
    send_file_end (1);                /* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    perror (dir);
    send_file_end (1);                /* Cancel. */
    return -1;
  }

  if (send_file_end (0))        /* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 3
0
/* Has one FileOut parameter. */
int
do_checksums_out (const char *csumtype, const char *dir)
{
  struct stat statbuf;
  int r;

  const char *program = program_of_csum (csumtype);
  if (program == NULL)
    return -1;

  CLEANUP_FREE char *sysrootdir = sysroot_path (dir);
  if (!sysrootdir) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = stat (sysrootdir, &statbuf);
  if (r == -1) {
    reply_with_perror ("%s", dir);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    return -1;
  }

  CLEANUP_FREE char *cmd = NULL;
  if (asprintf_nowarn (&cmd, "cd %Q && %s -type f -print0 | %s -0 %s",
                       sysrootdir, str_find, str_xargs, program) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  FILE *fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  char str[GUESTFS_MAX_CHUNK_SIZE];

  while ((r = fread (str, 1, GUESTFS_MAX_CHUNK_SIZE, fp)) > 0) {
    if (send_file_write (str, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    return -1;
  }

  if (send_file_end (0))        /* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 4
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_tar_out (const char *dir, const char *compress, int numericowner,
            char *const *excludes)
{
  CLEANUP_FREE char *buf = NULL;
  struct stat statbuf;
  const char *filter;
  int r;
  FILE *fp;
  CLEANUP_FREE char *excludes_args = NULL;
  CLEANUP_FREE char *cmd = NULL;
  char buffer[GUESTFS_MAX_CHUNK_SIZE];

  if ((optargs_bitmask & GUESTFS_TAR_OUT_COMPRESS_BITMASK)) {
    if (STREQ (compress, "compress"))
      filter = " --compress";
    else if (STREQ (compress, "gzip"))
      filter = " --gzip";
    else if (STREQ (compress, "bzip2"))
      filter = " --bzip2";
    else if (STREQ (compress, "xz"))
      filter = " --xz";
    else if (STREQ (compress, "lzop"))
      filter = " --lzop";
    else {
      reply_with_error ("unknown compression type: %s", compress);
      return -1;
    }
  } else
    filter = "";

  if (!(optargs_bitmask & GUESTFS_TAR_OUT_NUMERICOWNER_BITMASK))
    numericowner = 0;

  if ((optargs_bitmask & GUESTFS_TAR_OUT_EXCLUDES_BITMASK)) {
    excludes_args = make_excludes_args (excludes);
    if (!excludes_args)
      return -1;
  } else {
    excludes_args = strdup ("");
    if (excludes_args == NULL) {
      reply_with_perror ("strdup");
      return -1;
    }
  }

  /* Check the filename exists and is a directory (RHBZ#908322). */
  buf = sysroot_path (dir);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (stat (buf, &statbuf) == -1) {
    reply_with_perror ("stat: %s", dir);
    return -1;
  }

  if (! S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    return -1;
  }

  /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
  if (asprintf_nowarn (&cmd, "%s -C %s%s%s%s -cf - .",
                       str_tar,
                       buf, filter,
                       numericowner ? " --numeric-owner" : "",
                       excludes_args) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = fread (buffer, 1, sizeof buffer, fp)) > 0) {
    if (send_file_write (buffer, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", dir);
    send_file_end (1);		/* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", dir);
    send_file_end (1);		/* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 5
0
/* Has one FileOut parameter. */
int
do_find0 (const char *dir)
{
  struct stat statbuf;
  int r;
  FILE *fp;
  CLEANUP_FREE char *cmd = NULL;
  CLEANUP_FREE char *sysrootdir = NULL;
  size_t sysrootdirlen;
  CLEANUP_FREE char *str = NULL;

  str = malloc (GUESTFS_MAX_CHUNK_SIZE);
  if (str == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  sysrootdir = sysroot_path (dir);
  if (!sysrootdir) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = stat (sysrootdir, &statbuf);
  if (r == -1) {
    reply_with_perror ("%s", dir);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    return -1;
  }

  sysrootdirlen = strlen (sysrootdir);

  if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  /* The code below assumes each path returned can fit into a protocol
   * chunk (if not you'll get a runtime protocol error).  If this
   * turns out not to be a problem at some point in the future then
   * we'll need to modify the code to handle it.  XXX
   */
  while ((r = input_to_nul (fp, str, GUESTFS_MAX_CHUNK_SIZE)) > 0) {
    size_t len = strlen (str);
    if (len <= sysrootdirlen)
      continue;

    /* Remove the directory part of the path before sending it. */
    if (send_file_write (str + sysrootdirlen, r - sysrootdirlen) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fgetc: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    return -1;
  }

  if (send_file_end (0))        /* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 6
0
/* Has one FileOut parameter. */
static int
do_compressX_out (const char *file, const char *filter, int is_device)
{
  int r;
  FILE *fp;
  CLEANUP_FREE char *cmd = NULL;
  char buf[GUESTFS_MAX_CHUNK_SIZE];

  /* The command will look something like:
   *   gzip -c /sysroot%s     # file
   * or:
   *   gzip -c < %s           # device
   *
   * We have to quote the file or device name.
   *
   * The unnecessary redirect for devices is there because lzop
   * unhelpfully refuses to compress anything that isn't a regular
   * file.
   */
  if (!is_device) {
    if (asprintf_nowarn (&cmd, "%s %R", filter, file) == -1) {
      reply_with_perror ("asprintf");
      return -1;
    }
  } else {
    if (asprintf_nowarn (&cmd, "%s < %Q", filter, file) == -1) {
      reply_with_perror ("asprintf");
      return -1;
    }
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
    if (send_file_write (buf, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", file);
    send_file_end (1);		/* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", file);
    send_file_end (1);		/* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 7
0
/* Has one FileOut parameter. */
int
do_base64_out (const char *file)
{
  CLEANUP_FREE char *buf = NULL;
  struct stat statbuf;
  int r;
  FILE *fp;
  CLEANUP_FREE char *cmd = NULL;
  char buffer[GUESTFS_MAX_CHUNK_SIZE];

  /* Check the filename exists and is not a directory (RHBZ#908322). */
  buf = sysroot_path (file);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (stat (buf, &statbuf) == -1) {
    reply_with_perror ("stat: %s", file);
    return -1;
  }

  if (S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: is a directory", file);
    return -1;
  }

  /* Construct the command. */
  if (asprintf_nowarn (&cmd, "%s %Q", str_base64, buf) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = fread (buffer, 1, sizeof buffer, fp)) > 0) {
    if (send_file_write (buffer, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", file);
    send_file_end (1);		/* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", file);
    send_file_end (1);		/* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 8
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_ntfsclone_out (const char *device,
                  int metadataonly, int rescue, int ignorefscheck,
                  int preservetimestamps, int force)
{
  int r;
  FILE *fp;
  char *cmd;
  char buf[GUESTFS_MAX_CHUNK_SIZE];

  /* Construct the ntfsclone command. */
  if (asprintf (&cmd, "ntfsclone -o - --save-image%s%s%s%s%s %s",
                (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_METADATAONLY_BITMASK) && metadataonly ? " --metadata" : "",
                (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_RESCUE_BITMASK) && rescue ? " --rescue" : "",
                (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_IGNOREFSCHECK_BITMASK) && ignorefscheck ? " --ignore-fs-check" : "",
                (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_PRESERVETIMESTAMPS_BITMASK) && preservetimestamps ? " --preserve-timestamps" : "",
                (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_FORCE_BITMASK) && force ? " --force" : "",
                device) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    free (cmd);
    return -1;
  }
  free (cmd);

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
    if (send_file_write (buf, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    perror (device);
    send_file_end (1);		/* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    perror (device);
    send_file_end (1);		/* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}
Exemplo n.º 9
0
/* Has one FileOut parameter. */
int
do_ls0 (const char *path)
{
  DIR *dir;
  struct dirent *d;
  size_t len;

  CHROOT_IN;
  dir = opendir (path);
  CHROOT_OUT;

  if (dir == NULL) {
    reply_with_perror ("opendir: %s", path);
    return -1;
  }

  /* Now we must send the reply message, before the filenames.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while (1) {
    errno = 0;
    d = readdir (dir);
    if (d == NULL) break;

    /* Ignore . and .. */
    if (STREQ (d->d_name, ".") || STREQ (d->d_name, ".."))
      continue;

    /* Send the name in a single chunk.  XXX Needs to be fixed if
     * names can be longer than the chunk size.  Note we use 'len+1'
     * because we want to include the \0 terminating character in the
     * output.
     */
    len = strlen (d->d_name);
    if (send_file_write (d->d_name, len+1) < 0) {
      closedir (dir);
      return -1;
    }
  }

  if (errno != 0) {
    fprintf (stderr, "readdir: %s: %m\n", path);
    send_file_end (1);          /* Cancel. */
    closedir (dir);
    return -1;
  }

  if (closedir (dir) == -1) {
    fprintf (stderr, "closedir: %s: %m\n", path);
    send_file_end (1);          /* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}