diff --git a/builtin/odb--daemon.c b/builtin/odb--daemon.c index 6cccfd3ceb7f08..f1fd6a8ba9580e 100644 --- a/builtin/odb--daemon.c +++ b/builtin/odb--daemon.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "object-file.h" #include "object-store.h" #include "oidmap.h" #include "parse-options.h" @@ -8,6 +9,7 @@ #include "thread-utils.h" #include "odb-over-ipc.h" #include "trace2.h" +#include "hex.h" enum my_mode { MODE_UNDEFINED = 0, @@ -172,6 +174,44 @@ static int odb_ipc_cb__get_oid(struct my_odb_ipc_state *state, return 0; } +static int odb_ipc_cb__hash_object(struct my_odb_ipc_state *state, + const char *command, size_t command_len, + ipc_server_reply_cb *reply_cb, + struct ipc_server_reply_data *reply_data) +{ + struct odb_over_ipc__hash_object__request *req; + struct odb_over_ipc__hash_object__response *resp; + const char *content; + size_t content_len; + + if (command_len < sizeof(*req)) + BUG("incorrect size for binary data"); + + req = (struct odb_over_ipc__hash_object__request *)command; + + content = command + sizeof(*req); + content_len = command_len - sizeof(*req); + + resp = xmalloc(sizeof(*resp)); + memcpy(&resp->key.key, "hash-object", 11); + + if (index_mem(the_repository->index, &resp->oid, (void *)content, + content_len, req->type, NULL, req->flags) < 0) + goto fail; + + reply_cb(reply_data, (const char *)resp, sizeof(*resp)); + + return 0; + +fail: + /* + * Send the client an error response to force it to do + * the work itself. + */ + reply_cb(reply_data, "error", 6); + return 0; +} + /* * This callback handles IPC requests from clients. We run on an * arbitrary thread. @@ -226,6 +266,18 @@ static int odb_ipc_cb(void *data, return ret; } + if (!strcmp(command, "hash-object")) { + /* + * A client has requested that we hash an object and optionally + * store it in the ODB. + */ + trace2_region_enter("odb-daemon", "hash-object", NULL); + ret = odb_ipc_cb__hash_object(state, command, command_len, + reply_cb, reply_data); + trace2_region_leave("odb-daemon", "hash-object", NULL); + return 0; + } + // TODO respond to other requests from client. // // TODO decide how to return an error for unknown commands. diff --git a/object-file.c b/object-file.c index 2263f64c5ef2df..0ce79a8f241e8c 100644 --- a/object-file.c +++ b/object-file.c @@ -2490,10 +2490,10 @@ static int hash_format_check_report(struct fsck_options *opts UNUSED, return 1; } -static int index_mem(struct index_state *istate, - struct object_id *oid, void *buf, size_t size, - enum object_type type, - const char *path, unsigned flags) +int index_mem(struct index_state *istate, + struct object_id *oid, void *buf, size_t size, + enum object_type type, + const char *path, unsigned flags) { int ret = 0; int re_allocated = 0; @@ -2631,6 +2631,10 @@ int index_fd(struct index_state *istate, struct object_id *oid, enum object_type type, const char *path, unsigned flags) { int ret; + if (!odb_over_ipc__hash_object(the_repository, oid, fd, type, flags)) { + close(fd); + return 0; + } /* * Call xsize_t() only when needed to avoid potentially unnecessary diff --git a/object-file.h b/object-file.h index d6414610f80b73..416ae5d339851c 100644 --- a/object-file.h +++ b/object-file.h @@ -20,6 +20,7 @@ extern int fetch_if_missing; #define HASH_SILENT 8 int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); +int index_mem(struct index_state *istate, struct object_id *oid, void *buf, size_t size, enum object_type type, const char *path, unsigned flags); /* * Create the directory containing the named path, using care to be diff --git a/odb-over-ipc.c b/odb-over-ipc.c index 881024af4f50e2..1d342b71ebbebd 100644 --- a/odb-over-ipc.c +++ b/odb-over-ipc.c @@ -206,4 +206,62 @@ int odb_over_ipc__get_oid(struct repository *r, const struct object_id *oid, return ret; } +int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, + int fd, enum object_type type, unsigned flags) +{ + struct odb_over_ipc__hash_object__request req; + struct odb_over_ipc__hash_object__response *resp; + + struct strbuf answer = STRBUF_INIT; + struct strbuf content = STRBUF_INIT; + struct strbuf msg = STRBUF_INIT; + int ret; + + if (is_daemon) + return -1; + + if (!core_use_odb_over_ipc) + return -1; + + if (r != the_repository) // TODO not dealing with this + return -1; + + /* + * Read the content from the file descriptor in to the buffer and then + * send the request over IPC. + */ + if (strbuf_read(&content, fd, LARGE_PACKET_MAX) < 0) + return error_errno("could not read object content"); + + memset(&req, 0, sizeof(req)); + memcpy(req.key.key, "hash-object", 11); + req.type = type; + req.flags = flags; + req.content_size = content.len; + + /* Append the content at the end of the request */ + strbuf_init(&msg, sizeof(req) + content.len); + strbuf_add(&msg, &req, sizeof(req)); + strbuf_addbuf(&msg, &content); + + ret = odb_over_ipc__command((const char *)msg.buf, msg.len, &answer); + if (ret) + return ret; + + if (!strncmp(answer.buf, "error", 5)) { + trace2_printf("odb-over-ipc: failed"); + return -1; + } + + if (answer.len < sizeof(*resp)) + BUG("incorrect size for binary data"); + resp = (struct odb_over_ipc__hash_object__response *)answer.buf; + + oidcpy(oid, &resp->oid); + + strbuf_release(&content); + strbuf_release(&answer); + return ret; +} + #endif /* SUPPORTS_SIMPLE_IPC */ diff --git a/odb-over-ipc.h b/odb-over-ipc.h index 98524dd1c5015a..8fc1f27200731d 100644 --- a/odb-over-ipc.h +++ b/odb-over-ipc.h @@ -68,6 +68,20 @@ struct odb_over_ipc__get_oid__response enum object_type type; }; +struct odb_over_ipc__hash_object__request +{ + struct odb_over_ipc__key key; + enum object_type type; + unsigned flags; + size_t content_size; +}; + +struct odb_over_ipc__hash_object__response +{ + struct odb_over_ipc__key key; + struct object_id oid; +}; + /* * Connect to an existing `git odb--daemon` process and ask it for * an object. This is intended to be inserted into the client @@ -82,6 +96,10 @@ struct repository; int odb_over_ipc__get_oid(struct repository *r, const struct object_id *oid, struct object_info *oi, unsigned flags); + +int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, + int fd, enum object_type type, unsigned flags); + /* * Explicitly shutdown IPC connection to the `git odb--daemon` process. * The connection is implicitly created upon the first request and we