commit - b25ae4fac533cee8ef2910097b465d81abeb755f
commit + 500cd40f2b6e569ffb569fdeda0f2d1765324106
blob - e3f9b25018866888c25a81a14248c9a48d394d2e
blob + 0c72541adc1a32c762db1dc80b554e6cc37cc2b0
--- lib/fileindex.c
+++ lib/fileindex.c
entries = got_object_tree_get_entries(tree);
te = SIMPLEQ_FIRST(&entries->head);
- do {
+ while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || te) {
if (te && *ie) {
int cmp = cmp_entries((*ie)->path, path, path_len,
te->name);
if (err)
break;
}
- } while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || te);
+ }
return err;
}
const char *, struct got_repository *, struct got_fileindex_diff_dir_cb *,
void *);
+struct dirlist_entry {
+ SIMPLEQ_ENTRY(dirlist_entry) entry;
+ struct dirent *de;
+};
+SIMPLEQ_HEAD(dirlist_head, dirlist_entry);
+
static const struct got_error *
-walk_dir(struct dirent **next, struct got_fileindex *fileindex,
- struct got_fileindex_entry **ie, struct dirent *de, const char *path,
- DIR *dir, struct got_repository *repo,
+walk_dir(struct dirlist_entry **next, struct got_fileindex *fileindex,
+ struct got_fileindex_entry **ie, struct dirlist_entry *dle,
+ const char *path, DIR *dir, struct got_repository *repo,
struct got_fileindex_diff_dir_cb *cb, void *cb_arg)
{
const struct got_error *err = NULL;
- if (de->d_type == DT_DIR) {
+ if (dle->de->d_type == DT_DIR) {
char *subpath;
DIR *subdir;
if (asprintf(&subpath, "%s%s%s", path,
- path[0] == '\0' ? "" : "/", de->d_name) == -1)
+ path[0] == '\0' ? "" : "/", dle->de->d_name) == -1)
return got_error_from_errno();
subdir = opendir(subpath);
return err;
}
- *next = readdir(dir);
+ *next = SIMPLEQ_NEXT(dle, entry);
return NULL;
}
static const struct got_error *
+insert_dirent(struct dirlist_head *dirlist, struct dirent *de)
+{
+ struct dirlist_entry *dle, *prev = NULL;
+
+ /*
+ * Keep dirents sorted in same order as used by file index.
+ * Git orders tree object entries based on length and then memcmp().
+ */
+ SIMPLEQ_FOREACH(dle, dirlist, entry) {
+ int cmp;
+
+ if (dle->de->d_namlen > de->d_namlen) {
+ prev = dle;
+ continue;
+ }
+
+ cmp = strcmp(dle->de->d_name, de->d_name);
+ if (cmp == 0)
+ return NULL; /* duplicate, should not happen */
+ else if (cmp > 0)
+ break;
+ else
+ prev = dle;
+ }
+
+ dle = malloc(sizeof(*dle));
+ if (dle == NULL)
+ return got_error_from_errno();
+ dle->de = de;
+ if (prev)
+ SIMPLEQ_INSERT_AFTER(dirlist, prev, dle, entry);
+ else
+ SIMPLEQ_INSERT_HEAD(dirlist, dle, entry);
+
+ return NULL;
+}
+
+static const struct got_error *
diff_fileindex_dir(struct got_fileindex *fileindex,
struct got_fileindex_entry **ie, DIR *dir, const char *path,
struct got_repository *repo, struct got_fileindex_diff_dir_cb *cb,
struct dirent *de = NULL;
size_t path_len = strlen(path);
struct got_fileindex_entry *next;
+ struct dirlist_head dirlist;
+ struct dirlist_entry *dle;
- de = readdir(dir);
- do {
+ SIMPLEQ_INIT(&dirlist);
+
+ while (1) {
+ de = readdir(dir);
+ if (de == NULL)
+ break;
+
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0 ||
(path[0] == '\0' &&
- strcmp(de->d_name, GOT_WORKTREE_GOT_DIR) == 0)) {
- de = readdir(dir);
+ strcmp(de->d_name, GOT_WORKTREE_GOT_DIR) == 0))
continue;
- }
+ insert_dirent(&dirlist, de);
+ }
- if (de && *ie) {
+ dle = SIMPLEQ_FIRST(&dirlist);
+ while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || dle) {
+ if (dle && *ie) {
int cmp = cmp_entries((*ie)->path, path, path_len,
- de->d_name);
+ dle->de->d_name);
if (cmp == 0) {
- err = cb->diff_old_new(cb_arg, *ie, de, path);
+ err = cb->diff_old_new(cb_arg, *ie, dle->de,
+ path);
if (err)
break;
*ie = walk_fileindex(fileindex, *ie);
- err = walk_dir(&de, fileindex, ie, de, path,
+ err = walk_dir(&dle, fileindex, ie, dle, path,
dir, repo, cb, cb_arg);
} else if (cmp < 0 ) {
next = walk_fileindex(fileindex, *ie);
break;
*ie = next;
} else {
- err = cb->diff_new(cb_arg, de, path);
+ err = cb->diff_new(cb_arg, dle->de, path);
if (err)
break;
- err = walk_dir(&de, fileindex, ie, de, path,
+ err = walk_dir(&dle, fileindex, ie, dle, path,
dir, repo, cb, cb_arg);
}
if (err)
break;
}
- } while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || de);
+ }
+ while (!SIMPLEQ_EMPTY(&dirlist)) {
+ dle = SIMPLEQ_FIRST(&dirlist);
+ SIMPLEQ_REMOVE_HEAD(&dirlist, entry);
+ free(dle);
+ }
+
return err;
}