static gboolean
dispatch_bspatch (OstreeRepo                 *repo,
                  StaticDeltaExecutionState  *state,
                  GCancellable               *cancellable,
                  GError                    **error)
{
  gboolean ret = FALSE;
  guint64 offset, length;
  g_autoptr(GInputStream) in_stream = NULL;
  g_autoptr(GMappedFile) input_mfile = NULL;
  g_autofree guchar *buf = NULL;
  struct bspatch_stream stream;
  struct bzpatch_opaque_s opaque;
  gsize bytes_written;

  if (!read_varuint64 (state, &offset, error))
    goto out;
  if (!read_varuint64 (state, &length, error))
    goto out;

  if (!state->have_obj)
    {
      input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error);
      if (!input_mfile)
        goto out;

      buf = g_malloc0 (state->content_size);

      opaque.state = state;
      opaque.offset = offset;
      opaque.length = length;
      stream.read = bspatch_read;
      stream.opaque = &opaque;
      if (bspatch ((const guint8*)g_mapped_file_get_contents (input_mfile),
                   g_mapped_file_get_length (input_mfile),
                   buf,
                   state->content_size,
                   &stream) < 0)
        goto out;

      if (!g_output_stream_write_all (state->content_out,
                                      buf,
                                      state->content_size,
                                      &bytes_written,
                                      cancellable, error))
        goto out;

      g_assert (bytes_written == state->content_size);
    }

  ret = TRUE;
 out:
  return ret;
}
Exemple #2
0
static void
gum_darwin_mapper_init_cache_file (GumDarwinMapper * self,
                                   GumCpuType cpu_type)
{
  const gchar ** candidates, ** candidate;
  gint fd, result;

  switch (cpu_type)
  {
    case GUM_CPU_IA32:
      candidates = gum_darwin_cache_file_arch_candidates_ia32;
      break;
    case GUM_CPU_AMD64:
      candidates = gum_darwin_cache_file_arch_candidates_amd64;
      break;
    case GUM_CPU_ARM:
      candidates = gum_darwin_cache_file_arch_candidates_arm;
      break;
    case GUM_CPU_ARM64:
      candidates = gum_darwin_cache_file_arch_candidates_arm64;
      break;
    default:
      g_assert_not_reached ();
  }

  fd = -1;
  for (candidate = candidates; *candidate != NULL && fd == -1; candidate++)
  {
    gchar * path;

    path = g_strconcat (
        "/System/Library/Caches/com.apple.dyld/dyld_shared_cache_",
        *candidate,
        NULL);
    fd = open (path, 0);
    g_free (path);
  }
  if (fd == -1)
    return;

  result = fcntl (fd, F_NOCACHE, TRUE);
  g_assert (result == 0);

  self->cache_file = g_mapped_file_new_from_fd (fd, FALSE, NULL);
  g_assert (self->cache_file != NULL);

  close (fd);
}
Exemple #3
0
GBytes *
ot_file_mapat_bytes (int dfd,
                     const char *path,
                     GError **error)
{
  glnx_fd_close int fd = openat (dfd, path, O_RDONLY | O_CLOEXEC);
  g_autoptr(GMappedFile) mfile = NULL;

  if (fd < 0)
    {
      glnx_set_error_from_errno (error);
      return FALSE;
    }

  mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
  if (!mfile)
    return FALSE;

  return g_mapped_file_get_bytes (mfile);
}
Exemple #4
0
/**
 * Return in @out_variant the result of memory-mapping the entire
 * contents of file @src.
 *
 * Note the returned @out_variant is not floating.
 */
gboolean
ot_util_variant_map (GFile              *src,
                     const GVariantType *type,
                     gboolean            trusted,
                     GVariant          **out_variant,
                     GError            **error)
{
  gboolean ret = FALSE;
  const char *path = NULL;
  ot_lvariant GVariant *ret_variant = NULL;
  GMappedFile *mfile = NULL;
  int fd;

  path = ot_gfile_get_path_cached (src);
  if (!ot_unix_open_noatime (path, &fd, error))
    goto out;
  mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
  if (!mfile)
    goto out;
  if (!ot_unix_close (fd, error))
    goto out;

  ret_variant = g_variant_new_from_data (type,
                                         g_mapped_file_get_contents (mfile),
                                         g_mapped_file_get_length (mfile),
                                         trusted,
                                         (GDestroyNotify) g_mapped_file_unref,
                                         mfile);
  mfile = NULL;
  g_variant_ref_sink (ret_variant);
  
  ret = TRUE;
  ot_transfer_out_value(out_variant, &ret_variant);
 out:
  if (mfile)
    g_mapped_file_unref (mfile);
  return ret;
}
/**
 * gs_file_map_noatime: (skip)
 * @file: a #GFile
 * @cancellable: a #GCancellable
 * @error: a #GError
 *
 * Like g_mapped_file_new(), but try to avoid updating the file's
 * access time.  This should be used by background scanning
 * components such as search indexers, antivirus programs, etc.
 *
 * Returns: (transfer full): A new mapped file, or %NULL on error
 */
GMappedFile *
gs_file_map_noatime (GFile         *file,
                     GCancellable  *cancellable,
                     GError       **error)
{
    const char *path;
    int fd;
    GMappedFile *ret;

    if (g_cancellable_set_error_if_cancelled (cancellable, error))
        return NULL;

    path = gs_file_get_path_cached (file);
    if (path == NULL)
        return NULL;

    if (!gs_file_openat_noatime (AT_FDCWD, path, &fd, cancellable, error))
        return NULL;

    ret = g_mapped_file_new_from_fd (fd, FALSE, error);
    close_nointr_noerror (fd); /* Ignore errors - we always want to close */

    return ret;
}
static void
do_get (OtTrivialHttpd    *self,
        SoupServer        *server,
        SoupMessage       *msg,
        const char        *path,
        SoupClientContext *context)
{
  char *slash;
  int ret;
  struct stat stbuf;

  httpd_log (self, "serving %s\n", path);

  if (opt_expected_cookies)
    {
      GSList *cookies = soup_cookies_from_request (msg);
      GSList *l;
      int i;

      for (i = 0 ; opt_expected_cookies[i] != NULL; i++)
        {
          gboolean found = FALSE;
          gchar *k = opt_expected_cookies[i];
          gchar *v = strchr (k, '=') + 1;

          for (l = cookies;  l != NULL ; l = g_slist_next (l))
            {
              SoupCookie *c = l->data;

              if (!strncmp (k, soup_cookie_get_name (c), v - k - 1) &&
                  !strcmp (v, soup_cookie_get_value (c)))
                {
                  found = TRUE;
                  break;
                }
            }

          if (!found)
            {
              httpd_log (self, "Expected cookie not found %s\n", k);
              soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
              soup_cookies_free (cookies);
              goto out;
            }
        }
      soup_cookies_free (cookies);
    }

  if (opt_expected_headers)
    {
      for (int i = 0 ; opt_expected_headers[i] != NULL; i++)
        {
          const gchar *kv = opt_expected_headers[i];
          const gchar *eq = strchr (kv, '=');

          g_assert (eq);

          {
            g_autofree char *k = g_strndup (kv, eq - kv);
            const gchar *expected_v = eq + 1;
            const gchar *found_v = soup_message_headers_get_one (msg->request_headers, k);

            if (!found_v)
              {
                httpd_log (self, "Expected header not found %s\n", k);
                soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
                goto out;
              }
            if (strcmp (found_v, expected_v) != 0)
              {
                httpd_log (self, "Expected header %s: %s but found %s\n", k, expected_v, found_v);
                soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
                goto out;
              }
          }
        }
    }

  if (strstr (path, "../") != NULL)
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (opt_random_500s_percentage > 0 &&
      emitted_random_500s_count < opt_random_500s_max &&
      g_random_int_range (0, 100) < opt_random_500s_percentage)
    {
      emitted_random_500s_count++;
      soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  while (path[0] == '/')
    path++;

  do
    ret = fstatat (self->root_dfd, path, &stbuf, 0);
  while (ret == -1 && errno == EINTR);
  if (ret == -1)
    {
      if (errno == EPERM)
        soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      else if (errno == ENOENT)
        soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
      else
        soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  if (!is_safe_to_access (&stbuf))
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (S_ISDIR (stbuf.st_mode))
    {
      slash = strrchr (path, '/');
      if (!slash || slash[1])
        {
          g_autofree char *redir_uri = NULL;

          redir_uri = g_strdup_printf ("%s/", soup_message_get_uri (msg)->path);
          soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY,
                                     redir_uri);
        }
      else
        {
          g_autofree char *index_realpath = g_strconcat (path, "/index.html", NULL);
          if (fstatat (self->root_dfd, index_realpath, &stbuf, 0) != -1)
            {
              g_autofree char *index_path = g_strconcat (path, "/index.html", NULL);
              do_get (self, server, msg, index_path, context);
            }
          else
            {
              GString *listing = get_directory_listing (self->root_dfd, path);
              soup_message_set_response (msg, "text/html",
                                         SOUP_MEMORY_TAKE,
                                         listing->str, listing->len);
              soup_message_set_status (msg, SOUP_STATUS_OK);
              g_string_free (listing, FALSE);
            }
        }
    }
  else 
    {
      if (!S_ISREG (stbuf.st_mode))
        {
          soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
          goto out;
        }
      
      if (msg->method == SOUP_METHOD_GET)
        {
          glnx_autofd int fd = -1;
          g_autoptr(GMappedFile) mapping = NULL;
          gsize buffer_length, file_size;
          SoupRange *ranges;
          int ranges_length;
          gboolean have_ranges;

          fd = openat (self->root_dfd, path, O_RDONLY | O_CLOEXEC);
          if (fd < 0)
            {
              soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
              goto out;
            }

          mapping = g_mapped_file_new_from_fd (fd, FALSE, NULL);
          if (!mapping)
            {
              soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
              goto out;
            }
          (void) close (fd); fd = -1;

          file_size = g_mapped_file_get_length (mapping);
          have_ranges = soup_message_headers_get_ranges(msg->request_headers, file_size, &ranges, &ranges_length);
          if (opt_force_ranges && !have_ranges && g_strrstr (path, "/objects") != NULL)
            {
              SoupSocket *sock;
              buffer_length = file_size/2;
              soup_message_headers_set_content_length (msg->response_headers, file_size);
              soup_message_headers_append (msg->response_headers,
                                           "Connection", "close");

              /* soup-message-io will wait for us to add
               * another chunk after the first, to fill out
               * the declared Content-Length. Instead, we
               * forcibly close the socket at that point.
               */
              sock = soup_client_context_get_socket (context);
              g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock);
            }
          else
            buffer_length = file_size;

          if (have_ranges)
            {
              if (ranges_length > 0 && ranges[0].start >= file_size)
                {
                  soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
                  soup_message_headers_free_ranges (msg->request_headers, ranges);
                  goto out;
                }
              soup_message_headers_free_ranges (msg->request_headers, ranges);
            }
          if (buffer_length > 0)
            {
              SoupBuffer *buffer;

              buffer = soup_buffer_new_with_owner (g_mapped_file_get_contents (mapping),
                                                   buffer_length,
                                                   g_mapped_file_ref (mapping),
                                                   (GDestroyNotify)g_mapped_file_unref);
              soup_message_body_append_buffer (msg->response_body, buffer);
              soup_buffer_free (buffer);
            }
        }
      else /* msg->method == SOUP_METHOD_HEAD */
        {
          g_autofree char *length = NULL;

          /* We could just use the same code for both GET and
           * HEAD (soup-message-server-io.c will fix things up).
           * But we'll optimize and avoid the extra I/O.
           */
          length = g_strdup_printf ("%lu", (gulong)stbuf.st_size);
          soup_message_headers_append (msg->response_headers,
                                       "Content-Length", length);
        }
      soup_message_set_status (msg, SOUP_STATUS_OK);
    }
 out:
  {
    guint status = 0;
    g_autofree gchar *reason = NULL;

    g_object_get (msg,
                  "status-code", &status,
                  "reason-phrase", &reason,
                  NULL);
    httpd_log (self, "  status: %s (%u)\n", reason, status);
  }
  return;
}