1
+#include "cache.h"
2
+#include "bundle-uri.h"
3
+#include "bundle.h"
4
+#include "object-store.h"
5
+#include "refs.h"
6
+#include "run-command.h"
7
+
8
+static int find_temp_filename(struct strbuf *name)
9
+{
10
+ int fd;
11
+ /*
12
+ * Find a temporary filename that is available. This is briefly
13
+ * racy, but unlikely to collide.
14
+ */
15
+ fd = odb_mkstemp(name, "bundles/tmp_uri_XXXXXX");
16
+ if (fd < 0) {
17
+ warning(_("failed to create temporary file"));
18
+ return -1;
19
+ }
20
+
21
+ close(fd);
22
+ unlink(name->buf);
23
+ return 0;
24
+}
25
+
26
+static int copy_uri_to_file(const char *file, const char *uri)
27
+{
28
+ /* File-based URIs only for now. */
29
+ return copy_file(file, uri, 0);
30
+}
31
+
32
+static int unbundle_from_file(struct repository *r, const char *file)
33
+{
34
+ int result = 0;
35
+ int bundle_fd;
36
+ struct bundle_header header = BUNDLE_HEADER_INIT;
37
+ struct string_list_item *refname;
38
+ struct strbuf bundle_ref = STRBUF_INIT;
39
+ size_t bundle_prefix_len;
40
+
41
+ if ((bundle_fd = read_bundle_header(file, &header)) < 0)
42
+ return 1;
43
+
44
+ if ((result = unbundle(r, &header, bundle_fd, NULL)))
45
+ return 1;
46
+
47
+ /*
48
+ * Convert all refs/heads/ from the bundle into refs/bundles/
49
+ * in the local repository.
50
+ */
51
+ strbuf_addstr(&bundle_ref, "refs/bundles/");
52
+ bundle_prefix_len = bundle_ref.len;
53
+
54
+ for_each_string_list_item(refname, &header.references) {
55
+ struct object_id *oid = refname->util;
56
+ struct object_id old_oid;
57
+ const char *branch_name;
58
+ int has_old;
59
+
60
+ if (!skip_prefix(refname->string, "refs/heads/", &branch_name))
61
+ continue;
62
+
63
+ strbuf_setlen(&bundle_ref, bundle_prefix_len);
64
+ strbuf_addstr(&bundle_ref, branch_name);
65
+
66
+ has_old = !read_ref(bundle_ref.buf, &old_oid);
67
+ update_ref("fetched bundle", bundle_ref.buf, oid,
68
+ has_old ? &old_oid : NULL,
69
+ REF_SKIP_OID_VERIFICATION,
70
+ UPDATE_REFS_MSG_ON_ERR);
71
+ }
72
+
73
+ bundle_header_release(&header);
74
+ return result;
75
+}
76
+
77
+int fetch_bundle_uri(struct repository *r, const char *uri)
78
+{
79
+ int result = 0;
80
+ struct strbuf filename = STRBUF_INIT;
81
+
82
+ if ((result = find_temp_filename(&filename)))
83
+ goto cleanup;
84
+
85
+ if ((result = copy_uri_to_file(filename.buf, uri))) {
86
+ warning(_("failed to download bundle from URI '%s'"), uri);
87
+ goto cleanup;
88
+ }
89
+
90
+ if ((result = !is_bundle(filename.buf, 0))) {
91
+ warning(_("file at URI '%s' is not a bundle"), uri);
92
+ goto cleanup;
93
+ }
94
+
95
+ if ((result = unbundle_from_file(r, filename.buf))) {
96
+ warning(_("failed to unbundle bundle from URI '%s'"), uri);
97
+ goto cleanup;
98
+ }
99
+
100
+cleanup:
101
+ unlink(filename.buf);
102
+ strbuf_release(&filename);
103
+ return result;
104
+}