aboutsummaryrefslogtreecommitdiff
path: root/fast-import.c
diff options
context:
space:
mode:
Diffstat (limited to 'fast-import.c')
-rw-r--r--fast-import.c157
1 files changed, 112 insertions, 45 deletions
diff --git a/fast-import.c b/fast-import.c
index 89d074bbe..3c58e6f04 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -156,6 +156,7 @@ Format of STDIN stream:
#include "csum-file.h"
#include "quote.h"
#include "exec_cmd.h"
+#include "dir.h"
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -267,7 +268,7 @@ struct hash_list
typedef enum {
WHENSPEC_RAW = 1,
WHENSPEC_RFC2822,
- WHENSPEC_NOW,
+ WHENSPEC_NOW
} whenspec_type;
struct recent_command
@@ -361,6 +362,9 @@ static uintmax_t next_mark;
static struct strbuf new_data = STRBUF_INIT;
static int seen_data_command;
+/* Signal handling */
+static volatile sig_atomic_t checkpoint_requested;
+
static void parse_argv(void);
static void write_branch_report(FILE *rpt, struct branch *b)
@@ -500,6 +504,32 @@ static NORETURN void die_nicely(const char *err, va_list params)
exit(128);
}
+#ifndef SIGUSR1 /* Windows, for example */
+
+static void set_checkpoint_signal(void)
+{
+}
+
+#else
+
+static void checkpoint_signal(int signo)
+{
+ checkpoint_requested = 1;
+}
+
+static void set_checkpoint_signal(void)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = checkpoint_signal;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGUSR1, &sa, NULL);
+}
+
+#endif
+
static void alloc_objects(unsigned int cnt)
{
struct object_entry_pool *b;
@@ -975,29 +1005,6 @@ static void cycle_packfile(void)
start_packfile();
}
-static size_t encode_header(
- enum object_type type,
- uintmax_t size,
- unsigned char *hdr)
-{
- int n = 1;
- unsigned char c;
-
- if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
- die("bad type %d", type);
-
- c = (type << 4) | (size & 15);
- size >>= 4;
- while (size) {
- *hdr++ = c | 0x80;
- c = size & 0x7f;
- size >>= 7;
- n++;
- }
- *hdr = c;
- return n;
-}
-
static int store_object(
enum object_type type,
struct strbuf *dat,
@@ -1098,7 +1105,7 @@ static int store_object(
delta_count_by_type[type]++;
e->depth = last->depth + 1;
- hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
+ hdrlen = encode_in_pack_object_header(OBJ_OFS_DELTA, deltalen, hdr);
sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
@@ -1109,7 +1116,7 @@ static int store_object(
pack_size += sizeof(hdr) - pos;
} else {
e->depth = 0;
- hdrlen = encode_header(type, dat->len, hdr);
+ hdrlen = encode_in_pack_object_header(type, dat->len, hdr);
sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
}
@@ -1183,7 +1190,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
memset(&s, 0, sizeof(s));
deflateInit(&s, pack_compression_level);
- hdrlen = encode_header(OBJ_BLOB, len, out_buf);
+ hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf);
if (out_sz <= hdrlen)
die("impossibly large object header");
@@ -1455,6 +1462,20 @@ static void store_tree(struct tree_entry *root)
t->entry_count -= del;
}
+static void tree_content_replace(
+ struct tree_entry *root,
+ const unsigned char *sha1,
+ const uint16_t mode,
+ struct tree_content *newtree)
+{
+ if (!S_ISDIR(mode))
+ die("Root cannot be a non-directory");
+ hashcpy(root->versions[1].sha1, sha1);
+ if (root->tree)
+ release_tree_content_recursive(root->tree);
+ root->tree = newtree;
+}
+
static int tree_content_set(
struct tree_entry *root,
const char *p,
@@ -1462,7 +1483,7 @@ static int tree_content_set(
const uint16_t mode,
struct tree_content *subtree)
{
- struct tree_content *t = root->tree;
+ struct tree_content *t;
const char *slash1;
unsigned int i, n;
struct tree_entry *e;
@@ -1477,9 +1498,12 @@ static int tree_content_set(
if (!slash1 && !S_ISDIR(mode) && subtree)
die("Non-directories cannot have subtrees");
+ if (!root->tree)
+ load_tree(root);
+ t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
- if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
+ if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
if (!slash1) {
if (!S_ISDIR(mode)
&& e->versions[1].mode == mode
@@ -1532,7 +1556,7 @@ static int tree_content_remove(
const char *p,
struct tree_entry *backup_leaf)
{
- struct tree_content *t = root->tree;
+ struct tree_content *t;
const char *slash1;
unsigned int i, n;
struct tree_entry *e;
@@ -1543,9 +1567,20 @@ static int tree_content_remove(
else
n = strlen(p);
+ if (!root->tree)
+ load_tree(root);
+ t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
- if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
+ if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
+ if (slash1 && !S_ISDIR(e->versions[1].mode))
+ /*
+ * If p names a file in some subdirectory, and a
+ * file or symlink matching the name of the
+ * parent directory of p exists, then p cannot
+ * exist and need not be deleted.
+ */
+ return 1;
if (!slash1 || !S_ISDIR(e->versions[1].mode))
goto del_entry;
if (!e->tree)
@@ -1582,7 +1617,7 @@ static int tree_content_get(
const char *p,
struct tree_entry *leaf)
{
- struct tree_content *t = root->tree;
+ struct tree_content *t;
const char *slash1;
unsigned int i, n;
struct tree_entry *e;
@@ -1593,9 +1628,12 @@ static int tree_content_get(
else
n = strlen(p);
+ if (!root->tree)
+ load_tree(root);
+ t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
- if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
+ if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
if (!slash1) {
memcpy(leaf, e, sizeof(*leaf));
if (e->tree && is_null_sha1(e->versions[1].sha1))
@@ -1684,7 +1722,7 @@ static void dump_marks_helper(FILE *f,
if (m->shift) {
for (k = 0; k < 1024; k++) {
if (m->data.sets[k])
- dump_marks_helper(f, (base + k) << m->shift,
+ dump_marks_helper(f, base + (k << m->shift),
m->data.sets[k]);
}
} else {
@@ -2149,6 +2187,7 @@ static void file_change_m(struct branch *b)
case S_IFREG | 0644:
case S_IFREG | 0755:
case S_IFLNK:
+ case S_IFDIR:
case S_IFGITLINK:
/* ok */
break;
@@ -2194,25 +2233,34 @@ static void file_change_m(struct branch *b)
* another repository.
*/
} else if (inline_data) {
+ if (S_ISDIR(mode))
+ die("Directories cannot be specified 'inline': %s",
+ command_buf.buf);
if (p != uq.buf) {
strbuf_addstr(&uq, p);
p = uq.buf;
}
read_next_command();
parse_and_store_blob(&last_blob, sha1, 0);
- } else if (oe) {
- if (oe->type != OBJ_BLOB)
- die("Not a blob (actually a %s): %s",
- typename(oe->type), command_buf.buf);
} else {
- enum object_type type = sha1_object_info(sha1, NULL);
+ enum object_type expected = S_ISDIR(mode) ?
+ OBJ_TREE: OBJ_BLOB;
+ enum object_type type = oe ? oe->type :
+ sha1_object_info(sha1, NULL);
if (type < 0)
- die("Blob not found: %s", command_buf.buf);
- if (type != OBJ_BLOB)
- die("Not a blob (actually a %s): %s",
- typename(type), command_buf.buf);
+ die("%s not found: %s",
+ S_ISDIR(mode) ? "Tree" : "Blob",
+ command_buf.buf);
+ if (type != expected)
+ die("Not a %s (actually a %s): %s",
+ typename(expected), typename(type),
+ command_buf.buf);
}
+ if (!*p) {
+ tree_content_replace(&b->branch_tree, sha1, mode, NULL);
+ return;
+ }
tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
}
@@ -2271,6 +2319,13 @@ static void file_change_cr(struct branch *b, int rename)
tree_content_get(&b->branch_tree, s, &leaf);
if (!leaf.versions[1].mode)
die("Path %s not in branch", s);
+ if (!*d) { /* C "path/to/subdir" "" */
+ tree_content_replace(&b->branch_tree,
+ leaf.versions[1].sha1,
+ leaf.versions[1].mode,
+ leaf.tree);
+ return;
+ }
tree_content_set(&b->branch_tree, d,
leaf.versions[1].sha1,
leaf.versions[1].mode,
@@ -2684,14 +2739,20 @@ static void parse_reset_branch(void)
unread_command_buf = 1;
}
-static void parse_checkpoint(void)
+static void checkpoint(void)
{
+ checkpoint_requested = 0;
if (object_count) {
cycle_packfile();
dump_branches();
dump_tags();
dump_marks();
}
+}
+
+static void parse_checkpoint(void)
+{
+ checkpoint_requested = 1;
skip_optional_lf();
}
@@ -2725,6 +2786,7 @@ static void option_import_marks(const char *marks, int from_stream)
}
import_marks_file = make_fast_import_path(marks);
+ safe_create_leading_directories_const(import_marks_file);
import_marks_file_from_stream = from_stream;
}
@@ -2755,6 +2817,7 @@ static void option_active_branches(const char *branches)
static void option_export_marks(const char *marks)
{
export_marks_file = make_fast_import_path(marks);
+ safe_create_leading_directories_const(export_marks_file);
}
static void option_export_pack_edges(const char *edges)
@@ -2886,7 +2949,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
}
static const char fast_import_usage[] =
-"git fast-import [--date-format=f] [--max-pack-size=n] [--big-file-threshold=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
+"git fast-import [--date-format=<f>] [--max-pack-size=<n>] [--big-file-threshold=<n>] [--depth=<n>] [--active-branches=<n>] [--export-marks=<marks.file>]";
static void parse_argv(void)
{
@@ -2946,6 +3009,7 @@ int main(int argc, const char **argv)
prepare_packed_git();
start_packfile();
set_die_routine(die_nicely);
+ set_checkpoint_signal();
while (read_next_command() != EOF) {
if (!strcmp("blob", command_buf.buf))
parse_new_blob();
@@ -2967,6 +3031,9 @@ int main(int argc, const char **argv)
/* ignore non-git options*/;
else
die("Unsupported command: %s", command_buf.buf);
+
+ if (checkpoint_requested)
+ checkpoint();
}
/* argv hasn't been parsed yet, do so */