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; }
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); }
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); }
/** * 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; }