Example #1
0
/**
 * gs_fd_set_all_xattrs:
 * @fd: File descriptor
 * @xattrs: Extended attributes
 * @cancellable: Cancellable
 * @error: Error
 *
 * For each attribute in @xattrs, set its value on the file or
 * directory referred to by @fd.  This function does not remove any
 * attributes not in @xattrs.
 */
gboolean
gs_fd_set_all_xattrs (int            fd,
                      GVariant      *xattrs,
                      GCancellable  *cancellable,
                      GError       **error)
{
    return glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error);
}
Example #2
0
/*
 * checkout_tree_at:
 * @self: Repo
 * @mode: Options controlling all files
 * @overwrite_mode: Whether or not to overwrite files
 * @destination_parent_fd: Place tree here
 * @destination_name: Use this name for tree
 * @source: Source tree
 * @source_info: Source info
 * @cancellable: Cancellable
 * @error: Error
 *
 * Like ostree_repo_checkout_tree(), but check out @source into the
 * relative @destination_name, located by @destination_parent_fd.
 */
static gboolean
checkout_tree_at (OstreeRepo                        *self,
                  OstreeRepoCheckoutOptions         *options,
                  int                                destination_parent_fd,
                  const char                        *destination_name,
                  OstreeRepoFile                    *source,
                  GFileInfo                         *source_info,
                  GCancellable                      *cancellable,
                  GError                           **error)
{
  gboolean ret = FALSE;
  gboolean did_exist = FALSE;
  glnx_fd_close int destination_dfd = -1;
  int res;
  g_autoptr(GVariant) xattrs = NULL;
  g_autoptr(GFileEnumerator) dir_enum = NULL;

  /* Create initially with mode 0700, then chown/chmod only when we're
   * done.  This avoids anyone else being able to operate on partially
   * constructed dirs.
   */
  do
    res = mkdirat (destination_parent_fd, destination_name, 0700);
  while (G_UNLIKELY (res == -1 && errno == EINTR));
  if (res == -1)
    {
      if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
        did_exist = TRUE;
      else
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE,
                       &destination_dfd, error))
    goto out;

  /* Set the xattrs now, so any derived labeling works */
  if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
        goto out;

      if (xattrs)
        {
          if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error))
            goto out;
        }
    }

  if (g_file_info_get_file_type (source_info) != G_FILE_TYPE_DIRECTORY)
    {
      ret = checkout_one_file_at (self, options,
                                  (GFile *) source,
                                  source_info,
                                  destination_dfd,
                                  g_file_info_get_name (source_info),
                                  cancellable, error);
      goto out;
    }
  dir_enum = g_file_enumerate_children ((GFile*)source,
                                        OSTREE_GIO_FAST_QUERYINFO, 
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, 
                                        error);
  if (!dir_enum)
    goto out;

  while (TRUE)
    {
      GFileInfo *file_info;
      GFile *src_child;
      const char *name;

      if (!g_file_enumerator_iterate (dir_enum, &file_info, &src_child,
                                      cancellable, error))
        goto out;
      if (file_info == NULL)
        break;

      name = g_file_info_get_name (file_info);

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
          if (!checkout_tree_at (self, options,
                                 destination_dfd, name,
                                 (OstreeRepoFile*)src_child, file_info,
                                 cancellable, error))
            goto out;
        }
      else
        {
          if (!checkout_one_file_at (self, options,
                                     src_child, file_info,
                                     destination_dfd, name,
                                     cancellable, error))
            goto out;
        }
    }

  /* We do fchmod/fchown last so that no one else could access the
   * partially created directory and change content we're laying out.
   */
  if (!did_exist)
    {
      do
        res = fchmod (destination_dfd,
                      g_file_info_get_attribute_uint32 (source_info, "unix::mode"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      do
        res = fchown (destination_dfd,
                      g_file_info_get_attribute_uint32 (source_info, "unix::uid"),
                      g_file_info_get_attribute_uint32 (source_info, "unix::gid"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  /* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts.
   * Must be done after setting permissions and creating all children.
   */
  if (!did_exist)
    {
      const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} };
      do
        res = futimens (destination_dfd, times);
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (fsync_is_enabled (self, options))
    {
      if (fsync (destination_dfd) == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Example #3
0
static gboolean
write_regular_file_content (OstreeRepo            *self,
                            OstreeRepoCheckoutOptions *options,
                            GOutputStream         *output,
                            GFileInfo             *file_info,
                            GVariant              *xattrs,
                            GInputStream          *input,
                            GCancellable          *cancellable,
                            GError               **error)
{
  gboolean ret = FALSE;
  const OstreeRepoCheckoutMode mode = options->mode;
  int fd;
  int res;

  if (g_output_stream_splice (output, input, 0,
                              cancellable, error) < 0)
    goto out;

  if (!g_output_stream_flush (output, cancellable, error))
    goto out;

  fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)output);

  if (mode != OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      do
        res = fchown (fd,
                      g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
                      g_file_info_get_attribute_uint32 (file_info, "unix::gid"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }

      do
        res = fchmod (fd, g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
              
      if (xattrs)
        {
          if (!glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error))
            goto out;
        }
    }
          
  if (fsync_is_enabled (self, options))
    {
      if (fsync (fd) == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }
          
  if (!g_output_stream_close (output, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}