Esempio n. 1
0
/* Sets errno on error (!= 0), ENOSPC on short write */
int
copy_file (const char *src_path,
           const char *dst_path,
           mode_t      mode)
{
  int sfd;
  int dfd;
  int res;
  int errsv;

  sfd = open (src_path, O_CLOEXEC | O_RDONLY);
  if (sfd == -1)
    return -1;

  dfd = creat (dst_path, mode);
  if (dfd == -1)
    {
      errsv = errno;
      close (sfd);
      errno = errsv;
      return -1;
    }

  res = copy_file_data (sfd, dfd);

  errsv = errno;
  close (sfd);
  close (dfd);
  errno = errsv;

  return res;
}
Esempio n. 2
0
static int
append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
{
	struct archive_entry *in_entry;
	int e;

	while (0 == archive_read_next_header(ina, &in_entry)) {
		if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
			archive_entry_stat(in_entry)))
			continue;
		if (excluded(bsdtar, archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->option_interactive &&
		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->verbose)
			safe_fprintf(stderr, "a %s",
			    archive_entry_pathname(in_entry));
		siginfo_setinfo(bsdtar, "copying",
		    archive_entry_pathname(in_entry),
		    archive_entry_size(in_entry));
		siginfo_printinfo(bsdtar, 0);

		e = archive_write_header(a, in_entry);
		if (e != ARCHIVE_OK) {
			if (!bsdtar->verbose)
				bsdtar_warnc(bsdtar, 0, "%s: %s",
				    archive_entry_pathname(in_entry),
				    archive_error_string(a));
			else
				fprintf(stderr, ": %s", archive_error_string(a));
		}
		if (e == ARCHIVE_FATAL)
			exit(1);

		if (e >= ARCHIVE_WARN) {
			if (archive_entry_size(in_entry) == 0)
				archive_read_data_skip(ina);
			else if (copy_file_data(bsdtar, a, ina))
				exit(1);
		}

		if (bsdtar->verbose)
			fprintf(stderr, "\n");
	}

	/* Note: If we got here, we saw no write errors, so return success. */
	return (0);
}
Esempio n. 3
0
static int
append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
{
	struct archive_entry *in_entry;
	int e;

	while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) {
		if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
			archive_entry_stat(in_entry)))
			continue;
		if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->option_interactive &&
		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->verbose)
			safe_fprintf(stderr, "a %s",
			    archive_entry_pathname(in_entry));
		if (need_report())
			report_write(bsdtar, a, in_entry, 0);

		e = archive_write_header(a, in_entry);
		if (e != ARCHIVE_OK) {
			if (!bsdtar->verbose)
				lafe_warnc(0, "%s: %s",
				    archive_entry_pathname(in_entry),
				    archive_error_string(a));
			else
				fprintf(stderr, ": %s", archive_error_string(a));
		}
		if (e == ARCHIVE_FATAL)
			exit(1);

		if (e >= ARCHIVE_WARN) {
			if (archive_entry_size(in_entry) == 0)
				archive_read_data_skip(ina);
			else if (copy_file_data(bsdtar, a, ina, in_entry))
				exit(1);
		}

		if (bsdtar->verbose)
			fprintf(stderr, "\n");
	}

	return (e == ARCHIVE_EOF ? ARCHIVE_OK : e);
}
Esempio n. 4
0
int file_copy(const char *src, const char *dest)
{
    struct stat src_stat;
    struct stat dest_stat;
    int dest_exists = 1;
    int status = 0;
    int r;

    r = stat(src, &src_stat);
    if (r < 0) {
        opkg_perror(ERROR, "%s", src);
        return -1;
    }

    r = stat(dest, &dest_stat);
    if (r < 0) {
        if (errno != ENOENT) {
            opkg_perror(ERROR, "unable to stat `%s'", dest);
            return -1;
        }
        dest_exists = 0;
    } else {
        int is_same_file = (src_stat.st_rdev == dest_stat.st_rdev
                && src_stat.st_ino == dest_stat.st_ino);
        if (is_same_file) {
            opkg_msg(ERROR, "`%s' and `%s' are the same file.\n", src, dest);
            return -1;
        }
    }

    if (S_ISREG(src_stat.st_mode)) {
        FILE *sfp, *dfp;
        struct utimbuf times;

        if (dest_exists) {
            dfp = fopen(dest, "w");
            if (dfp == NULL) {
                r = unlink(dest);
                if (r < 0) {
                    opkg_perror(ERROR, "unable to remove `%s'", dest);
                    return -1;
                }
            }
        } else {
            int fd;

            fd = open(dest, O_WRONLY | O_CREAT, src_stat.st_mode);
            if (fd < 0) {
                opkg_perror(ERROR, "unable to open `%s'", dest);
                return -1;
            }
            dfp = fdopen(fd, "w");
            if (dfp == NULL) {
                if (fd >= 0)
                    close(fd);
                opkg_perror(ERROR, "unable to open `%s'", dest);
                return -1;
            }
        }

        sfp = fopen(src, "r");
        if (sfp) {
            r = copy_file_data(sfp, dfp);
            if (r < 0)
                status = -1;

            r = fclose(sfp);
            if (r < 0) {
                opkg_perror(ERROR, "unable to close `%s'", src);
                status = -1;
            }
        } else {
            opkg_perror(ERROR, "unable to open `%s'", src);
            status = -1;
        }

        r = fclose(dfp);
        if (r < 0) {
            opkg_perror(ERROR, "unable to close `%s'", dest);
            status = -1;
        }

        times.actime = src_stat.st_atime;
        times.modtime = src_stat.st_mtime;
        r = utime(dest, &times);
        if (r < 0)
            opkg_perror(ERROR, "unable to preserve times of `%s'", dest);

        r = chown(dest, src_stat.st_uid, src_stat.st_gid);
        if (r < 0) {
            src_stat.st_mode &= ~(S_ISUID | S_ISGID);
            opkg_perror(ERROR, "unable to preserve ownership of `%s'", dest);
        }

        r = chmod(dest, src_stat.st_mode);
        if (r < 0)
            opkg_perror(ERROR, "unable to preserve permissions of `%s'", dest);

        return status;
    } else if (S_ISBLK(src_stat.st_mode) || S_ISCHR(src_stat.st_mode)
               || S_ISSOCK(src_stat.st_mode)) {
        r = mknod(dest, src_stat.st_mode, src_stat.st_rdev);
        if (r < 0) {
            opkg_perror(ERROR, "unable to create `%s'", dest);
            return -1;
        }
    } else if (S_ISFIFO(src_stat.st_mode)) {
        r = mkfifo(dest, src_stat.st_mode);
        if (r < 0) {
            opkg_perror(ERROR, "cannot create fifo `%s'", dest);
            return -1;
        }
    } else if (S_ISDIR(src_stat.st_mode)) {
        opkg_msg(ERROR, "%s: omitting directory.\n", src);
        return -1;
    }

    opkg_msg(ERROR, "internal error: unrecognized file type.\n");
    return -1;
}
Esempio n. 5
0
static int
handle_overwrite_open (const char    *filename,
		       const char    *etag,
		       gboolean       create_backup,
		       char         **temp_filename,
		       GCancellable  *cancellable,
		       GError       **error)
{
  int fd = -1;
  GLocalFileStat original_stat;
  char *current_etag;
  gboolean is_symlink;
  int open_flags;
  int res;

  /* We only need read access to the original file if we are creating a backup.
   * We also add O_CREATE to avoid a race if the file was just removed */
  if (create_backup)
    open_flags = O_RDWR | O_CREAT | O_BINARY;
  else
    open_flags = O_WRONLY | O_CREAT | O_BINARY;
  
  /* Some systems have O_NOFOLLOW, which lets us avoid some races
   * when finding out if the file we opened was a symlink */
#ifdef O_NOFOLLOW
  is_symlink = FALSE;
  fd = g_open (filename, open_flags | O_NOFOLLOW, 0666);
  if (fd == -1 && errno == ELOOP)
    {
      /* Could be a symlink, or it could be a regular ELOOP error,
       * but then the next open will fail too. */
      is_symlink = TRUE;
      fd = g_open (filename, open_flags, 0666);
    }
#else
  fd = g_open (filename, open_flags, 0666);
  /* This is racy, but we do it as soon as possible to minimize the race */
  is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
#endif
    
  if (fd == -1)
    {
      int errsv = errno;
      char *display_name = g_filename_display_name (filename);
      g_set_error (error, G_IO_ERROR,
		   g_io_error_from_errno (errsv),
		   _("Error opening file '%s': %s"),
		   display_name, g_strerror (errsv));
      g_free (display_name);
      return -1;
    }
  
#ifdef G_OS_WIN32
  res = _fstati64 (fd, &original_stat);
#else
  res = fstat (fd, &original_stat);
#endif

  if (res != 0) 
    {
      int errsv = errno;
      char *display_name = g_filename_display_name (filename);
      g_set_error (error, G_IO_ERROR,
		   g_io_error_from_errno (errsv),
		   _("Error stating file '%s': %s"),
		   display_name, g_strerror (errsv));
      g_free (display_name);
      goto err_out;
    }
  
  /* not a regular file */
  if (!S_ISREG (original_stat.st_mode))
    {
      if (S_ISDIR (original_stat.st_mode))
	g_set_error_literal (error,
                             G_IO_ERROR,
                             G_IO_ERROR_IS_DIRECTORY,
                             _("Target file is a directory"));
      else
	g_set_error_literal (error,
                             G_IO_ERROR,
                             G_IO_ERROR_NOT_REGULAR_FILE,
                             _("Target file is not a regular file"));
      goto err_out;
    }
  
  if (etag != NULL)
    {
      current_etag = _g_local_file_info_create_etag (&original_stat);
      if (strcmp (etag, current_etag) != 0)
	{
	  g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_WRONG_ETAG,
                               _("The file was externally modified"));
	  g_free (current_etag);
	  goto err_out;
	}
      g_free (current_etag);
    }

  /* We use two backup strategies.
   * The first one (which is faster) consist in saving to a
   * tmp file then rename the original file to the backup and the
   * tmp file to the original name. This is fast but doesn't work
   * when the file is a link (hard or symbolic) or when we can't
   * write to the current dir or can't set the permissions on the
   * new file. 
   * The second strategy consist simply in copying the old file
   * to a backup file and rewrite the contents of the file.
   */
  
  if (!(original_stat.st_nlink > 1) && !is_symlink)
    {
      char *dirname, *tmp_filename;
      int tmpfd;
      
      dirname = g_path_get_dirname (filename);
      tmp_filename = g_build_filename (dirname, ".goutputstream-XXXXXX", NULL);
      g_free (dirname);

      tmpfd = g_mkstemp (tmp_filename);
      if (tmpfd == -1)
	{
	  g_free (tmp_filename);
	  goto fallback_strategy;
	}
      
      /* try to keep permissions */

      if (
#ifdef HAVE_FCHOWN
	  fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
#endif
#ifdef HAVE_FCHMOD
	  fchmod (tmpfd, original_stat.st_mode) == -1 ||
#endif
	  0
	  )
	{
	  struct stat tmp_statbuf;
	  
	  /* Check that we really needed to change something */
	  if (fstat (tmpfd, &tmp_statbuf) != 0 ||
	      original_stat.st_uid != tmp_statbuf.st_uid ||
	      original_stat.st_gid != tmp_statbuf.st_gid ||
	      original_stat.st_mode != tmp_statbuf.st_mode)
	    {
	      close (tmpfd);
	      g_unlink (tmp_filename);
	      g_free (tmp_filename);
	      goto fallback_strategy;
	    }
	}

      close (fd);
      *temp_filename = tmp_filename;
      return tmpfd;
    }

 fallback_strategy:

  if (create_backup)
    {
#if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
      struct stat tmp_statbuf;      
#endif
      char *backup_filename;
      int bfd;
      
      backup_filename = create_backup_filename (filename);

      if (g_unlink (backup_filename) == -1 && errno != ENOENT)
	{
	  g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_CANT_CREATE_BACKUP,
                               _("Backup file creation failed"));
	  g_free (backup_filename);
	  goto err_out;
	}

      bfd = g_open (backup_filename,
		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
		    original_stat.st_mode & 0777);

      if (bfd == -1)
	{
	  g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_CANT_CREATE_BACKUP,
                               _("Backup file creation failed"));
	  g_free (backup_filename);
	  goto err_out;
	}

      /* If needed, Try to set the group of the backup same as the
       * original file. If this fails, set the protection
       * bits for the group same as the protection bits for
       * others. */
#if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
      if (fstat (bfd, &tmp_statbuf) != 0)
	{
	  g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_CANT_CREATE_BACKUP,
                               _("Backup file creation failed"));
	  g_unlink (backup_filename);
	  g_free (backup_filename);
	  goto err_out;
	}
      
      if ((original_stat.st_gid != tmp_statbuf.st_gid)  &&
	  fchown (bfd, (uid_t) -1, original_stat.st_gid) != 0)
	{
	  if (fchmod (bfd,
		      (original_stat.st_mode & 0707) |
		      ((original_stat.st_mode & 07) << 3)) != 0)
	    {
	      g_set_error_literal (error,
                                   G_IO_ERROR,
                                   G_IO_ERROR_CANT_CREATE_BACKUP,
                                   _("Backup file creation failed"));
	      g_unlink (backup_filename);
	      close (bfd);
	      g_free (backup_filename);
	      goto err_out;
	    }
	}
#endif

      if (!copy_file_data (fd, bfd, NULL))
	{
	  g_set_error_literal (error,
                               G_IO_ERROR,
                               G_IO_ERROR_CANT_CREATE_BACKUP,
                               _("Backup file creation failed"));
	  g_unlink (backup_filename);
	  close (bfd);
	  g_free (backup_filename);
	  
	  goto err_out;
	}
      
      close (bfd);
      g_free (backup_filename);

      /* Seek back to the start of the file after the backup copy */
      if (lseek (fd, 0, SEEK_SET) == -1)
	{
          int errsv = errno;

	  g_set_error (error, G_IO_ERROR,
		       g_io_error_from_errno (errsv),
		       _("Error seeking in file: %s"),
		       g_strerror (errsv));
	  goto err_out;
	}
    }

  /* Truncate the file at the start */
#ifdef G_OS_WIN32
  if (g_win32_ftruncate (fd, 0) == -1)
#else
  if (ftruncate (fd, 0) == -1)
#endif
    {
      int errsv = errno;

      g_set_error (error, G_IO_ERROR,
		   g_io_error_from_errno (errsv),
		   _("Error truncating file: %s"),
		   g_strerror (errsv));
      goto err_out;
    }
    
  return fd;

 err_out:
  close (fd);
  return -1;
}
Esempio n. 6
0
static int
append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina,
    void * cookie)
{
	struct archive_entry *in_entry;
	int e;

	while (0 == archive_read_next_header(ina, &in_entry)) {
		if (truncate_archive(bsdtar))
			break;
		if (checkpoint_archive(bsdtar, 0))
			exit(1);
		if (cookie == NULL)
			disk_pause(bsdtar);
		if (network_select(0))
			exit(1);

		if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
			archive_entry_stat(in_entry)))
			continue;
		if (excluded(bsdtar, archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->option_interactive &&
		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
			continue;
		if (bsdtar->verbose)
			safe_fprintf(stderr, "a %s",
			    archive_entry_pathname(in_entry));
		siginfo_setinfo(bsdtar, "copying",
		    archive_entry_pathname(in_entry),
		    archive_entry_size(in_entry));
		siginfo_printinfo(bsdtar, 0);

		if (MODE_HEADER(bsdtar, a))
			goto err_fatal;
		e = archive_write_header(a, in_entry);
		if (e != ARCHIVE_OK) {
			if (!bsdtar->verbose)
				bsdtar_warnc(bsdtar, 0, "%s: %s",
				    archive_entry_pathname(in_entry),
				    archive_error_string(a));
			else
				fprintf(stderr, ": %s", archive_error_string(a));
		}
		if (e == ARCHIVE_FATAL)
			exit(1);
		if (e < ARCHIVE_WARN)
			goto done;

		if (MODE_DATA(bsdtar, a))
			goto err_fatal;

		if (archive_entry_size(in_entry) == 0)
			archive_read_data_skip(ina);
		else if (cookie == NULL) {
			if (copy_file_data(bsdtar, a, ina))
				exit(1);
		} else {
			switch (archive_multitape_copy(ina, cookie, a,
			    bsdtar->write_cookie)) {
			case -1:
				goto err_fatal;
			case -2:
				goto err_read;
			}
		}

done:
		if (MODE_DONE(bsdtar, a))
			goto err_fatal;
		if (bsdtar->verbose)
			fprintf(stderr, "\n");
		continue;

err_read:
		bsdtar->return_value = 1;
		if (MODE_DONE(bsdtar, a))
			goto err_fatal;
		if (bsdtar->verbose)
			fprintf(stderr, "\n");
		break;

err_fatal:
		bsdtar_warnc(bsdtar, archive_errno(a), "%s",
		    archive_error_string(a));
		exit(1);
	}

	/* Note: If we got here, we saw no write errors, so return success. */
	return (0);
}
Esempio n. 7
0
static void
setup_newroot (bool unshare_pid,
               int privileged_op_socket)
{
  SetupOp *op;

  for (op = ops; op != NULL; op = op->next)
    {
      cleanup_free char *source = NULL;
      cleanup_free char *dest = NULL;
      int source_mode = 0;
      int i;

      if (op->source &&
          op->type != SETUP_MAKE_SYMLINK)
        {
          source = get_oldroot_path (op->source);
          source_mode = get_file_mode (source);
          if (source_mode < 0)
            die_with_error ("Can't get type of source %s", op->source);
        }

      if (op->dest)
        {
          dest = get_newroot_path (op->dest);
          if (mkdir_with_parents (dest, 0755, FALSE) != 0)
            die_with_error ("Can't mkdir parents for %s", op->dest);
        }

      switch (op->type) {
      case SETUP_RO_BIND_MOUNT:
      case SETUP_DEV_BIND_MOUNT:
      case SETUP_BIND_MOUNT:
        if (source_mode == S_IFDIR)
          {
            if (mkdir (dest, 0755) != 0 && errno != EEXIST)
              die_with_error ("Can't mkdir %s", op->dest);
          }
        else
          {
            if (ensure_file (dest, 0666) != 0)
              die_with_error ("Can't create file at %s", op->dest);
          }

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_BIND_MOUNT,
                       (op->type == SETUP_RO_BIND_MOUNT ? BIND_READONLY : 0) |
                       (op->type == SETUP_DEV_BIND_MOUNT ? BIND_DEVICES : 0),
                       source, dest);
        break;

      case SETUP_MOUNT_PROC:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        if (unshare_pid)
          {
            /* Our own procfs */
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_PROC_MOUNT, 0,
                           dest, NULL);
          }
        else
          {
            /* Use system procfs, as we share pid namespace anyway */
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, 0,
                           "oldroot/proc", dest);
          }

        /* There are a bunch of weird old subdirs of /proc that could potentially be
           problematic (for instance /proc/sysrq-trigger lets you shut down the machine
           if you have write access). We should not have access to these as a non-privileged
           user, but lets cover them anyway just to make sure */
        const char *cover_proc_dirs[] = { "sys", "sysrq-trigger", "irq", "bus" };
        for (i = 0; i < N_ELEMENTS (cover_proc_dirs); i++)
          {
            cleanup_free char *subdir = strconcat3 (dest, "/", cover_proc_dirs[i]);
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_READONLY,
                           subdir, subdir);
          }

        break;

      case SETUP_MOUNT_DEV:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_TMPFS_MOUNT, 0,
                       dest, NULL);

        static const char *const devnodes[] = { "null", "zero", "full", "random", "urandom", "tty" };
        for (i = 0; i < N_ELEMENTS (devnodes); i++)
          {
            cleanup_free char *node_dest = strconcat3 (dest, "/", devnodes[i]);
            cleanup_free char *node_src = strconcat ("/oldroot/dev/", devnodes[i]);
            if (create_file (node_dest, 0666, NULL) != 0)
              die_with_error ("Can't create file %s/%s", op->dest, devnodes[i]);
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES,
                           node_src, node_dest);
          }

        static const char *const stdionodes[] = { "stdin", "stdout", "stderr" };
        for (i = 0; i < N_ELEMENTS (stdionodes); i++)
          {
            cleanup_free char *target = xasprintf ("/proc/self/fd/%d", i);
            cleanup_free char *node_dest = strconcat3 (dest, "/", stdionodes[i]);
            if (symlink (target, node_dest) < 0)
              die_with_error ("Can't create symlink %s/%s", op->dest, stdionodes[i]);
          }

        {
          cleanup_free char *pts = strconcat (dest, "/pts");
          cleanup_free char *ptmx = strconcat (dest, "/ptmx");
          cleanup_free char *shm = strconcat (dest, "/shm");

          if (mkdir (shm, 0755) == -1)
            die_with_error ("Can't create %s/shm", op->dest);

          if (mkdir (pts, 0755) == -1)
            die_with_error ("Can't create %s/devpts", op->dest);
          privileged_op (privileged_op_socket,
                         PRIV_SEP_OP_DEVPTS_MOUNT, BIND_DEVICES,
                         pts, NULL);

          if (symlink ("pts/ptmx", ptmx) != 0)
            die_with_error ("Can't make symlink at %s/ptmx", op->dest);
        }

        /* If stdout is a tty, that means the sandbox can write to the
           outside-sandbox tty. In that case we also create a /dev/console
           that points to this tty device. This should not cause any more
           access than we already have, and it makes ttyname() work in the
           sandbox. */
        if (host_tty_dev != NULL && *host_tty_dev != 0)
          {
            cleanup_free char *src_tty_dev = strconcat ("/oldroot", host_tty_dev);
            cleanup_free char *dest_console = strconcat (dest, "/console");

            if (create_file (dest_console, 0666, NULL) != 0)
              die_with_error ("creating %s/console", op->dest);

            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES,
                           src_tty_dev, dest_console);
          }

        break;

      case SETUP_MOUNT_TMPFS:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_TMPFS_MOUNT, 0,
                       dest, NULL);
        break;
      case SETUP_MOUNT_MQUEUE:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_MQUEUE_MOUNT, 0,
                       dest, NULL);
        break;
      case SETUP_MAKE_DIR:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        break;

      case SETUP_MAKE_FILE:
        {
          cleanup_fd int dest_fd = -1;

          dest_fd = creat (dest, 0666);
          if (dest_fd == -1)
            die_with_error ("Can't create file %s", op->dest);

          if (copy_file_data (op->fd, dest_fd) != 0)
            die_with_error ("Can't write data to file %s", op->dest);

          close (op->fd);
        }
        break;

      case SETUP_MAKE_BIND_FILE:
        {
          cleanup_fd int dest_fd = -1;
          char tempfile[] = "/bindfileXXXXXX";

          dest_fd = mkstemp (tempfile);
          if (dest_fd == -1)
            die_with_error ("Can't create tmpfile for %s", op->dest);

          if (copy_file_data (op->fd, dest_fd) != 0)
            die_with_error ("Can't write data to file %s", op->dest);

          close (op->fd);

          if (ensure_file (dest, 0666) != 0)
            die_with_error ("Can't create file at %s", op->dest);

          privileged_op (privileged_op_socket,
                         PRIV_SEP_OP_BIND_MOUNT,
                         0, tempfile, dest);
        }
        break;

      case SETUP_MAKE_SYMLINK:
        if (symlink (op->source, dest) != 0)
          die_with_error ("Can't make symlink at %s", op->dest);
        break;

      default:
        die ("Unexpected type %d", op->type);
      }
    }
  privileged_op (privileged_op_socket,
                 PRIV_SEP_OP_DONE, 0, NULL, NULL);
}