commit - 7afec891490adf4fd7cdcfe668cba0d7b2401de5
commit + e0857cfe46baca2f87986268f7d819b8bd9591ff
blob - 6eac9e32b7726497913a225ac7e1e99a4d727ece
blob + 6a927f23e171745f70fa35dc25632bbd016df870
--- gotweb/gotweb.c
+++ gotweb/gotweb.c
char *, char *, int);
static const struct got_error *gw_get_file_blame_blob(char **,
struct gw_trans *);
-static const struct got_error *gw_get_file_read_blob(char **, size_t *,
- struct gw_trans *);
+static const struct got_error *gw_output_blob_buf(struct gw_trans *);
static const struct got_error *gw_get_repo_tree(char **, struct gw_trans *);
static const struct got_error *gw_get_diff(struct gw_trans *,
struct gw_header *);
}
static int
-isbinary(const char *buf, size_t n)
+isbinary(const uint8_t *buf, size_t n)
{
- return (memchr(buf, '\0', n) != NULL);
+ size_t i;
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++)
+ if (buf[i] == 0)
+ return 1;
+ return 0;
}
static const struct got_error *
{
const struct got_error *error = NULL;
struct gw_header *header = NULL;
- char *content = NULL;
- size_t filesize = 0;
- enum kcgi_err kerr;
if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
NULL) == -1)
if (error)
goto done;
- error = gw_get_file_read_blob(&content, &filesize, gw_trans);
- if (error)
- goto done;
-
- if (isbinary(content, filesize))
- gw_trans->mime = KMIME_APP_OCTET_STREAM;
- else
- gw_trans->mime = KMIME_TEXT_PLAIN;
-
- error = gw_display_index(gw_trans);
- if (error)
- goto done;
-
- kerr = khttp_write(gw_trans->gw_req, content, filesize);
- if (kerr != KCGI_OK)
- error = gw_kcgi_error(kerr);
+ error = gw_output_blob_buf(gw_trans);
done:
got_ref_list_free(&header->refs);
gw_free_headers(header);
- free(content);
return error;
}
}
static const struct got_error *
-gw_get_file_read_blob(char **blobstr, size_t *filesize, struct gw_trans *gw_trans)
+gw_output_blob_buf(struct gw_trans *gw_trans)
{
const struct got_error *error = NULL;
struct got_repository *repo = NULL;
struct got_object_id *commit_id = NULL;
struct got_blob_object *blob = NULL;
char *path = NULL, *in_repo_path = NULL;
- int obj_type;
- size_t n;
- FILE *f = NULL;
+ int obj_type, set_mime = 0;
+ size_t len, hdrlen;
+ const uint8_t *buf;
+ enum kcgi_err kerr = KCGI_OK;
- *blobstr = NULL;
- *filesize = 0;
-
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
if (error)
return error;
}
error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
- if (error)
- goto done;
-
- f = got_opentemp();
- if (f == NULL) {
- error = got_error_from_errno("got_opentemp");
- goto done;
- }
- error = got_object_blob_dump_to_file(filesize, NULL, NULL, f, blob);
if (error)
goto done;
- /* XXX This will fail on large files... */
- *blobstr = calloc(*filesize + 1, sizeof(**blobstr));
- if (*blobstr == NULL) {
- error = got_error_from_errno("calloc");
- goto done;
- }
+ hdrlen = got_object_blob_get_hdrlen(blob);
+ do {
+ error = got_object_blob_read_block(&len, blob);
+ if (error)
+ goto done;
+ if (len == 0)
+ break;
+ buf = got_object_blob_get_read_buf(blob);
- n = fread(*blobstr, 1, *filesize, f);
- if (n == 0) {
- if (ferror(f))
- error = got_ferror(f, GOT_ERR_IO);
- goto done;
- }
+ /*
+ * Skip blob object header first time around,
+ * which also contains a zero byte.
+ */
+ buf += hdrlen;
+ if (set_mime == 0) {
+ if (isbinary(buf, len - hdrlen))
+ gw_trans->mime = KMIME_APP_OCTET_STREAM;
+ else
+ gw_trans->mime = KMIME_TEXT_PLAIN;
+ set_mime = 1;
+ error = gw_display_index(gw_trans);
+ if (error)
+ goto done;
+ }
+ khttp_write(gw_trans->gw_req, buf, len - hdrlen);
+ hdrlen = 0;
+ } while (len != 0);
done:
free(in_repo_path);
free(commit_id);
got_object_blob_close(blob);
if (repo)
got_repo_close(repo);
- if (f != NULL && fclose(f) == -1 && error == NULL)
- error = got_error_from_errno("fclose");
- if (error) {
- free(*blobstr);
- *blobstr = NULL;
- *filesize = 0;
- }
+ if (error == NULL && kerr != KCGI_OK)
+ error = gw_kcgi_error(kerr);
return error;
}