commit - a062651c55aa60f0633437e9851dd80b1d713e86
commit + c577a9cecea0c94f30a1e650e6e332fb8b43b9f6
blob - 8ff467458d80b3a0f400b0b4b668affadbc2a12a
blob + 0e62e71ac79879c8427c88f483ad9505a3d27f18
--- lib/fileindex.c
+++ lib/fileindex.c
static const struct got_error *
diff_fileindex_dir(struct got_fileindex *, struct got_fileindex_entry **, DIR *,
- const char *, const char *, struct got_repository *,
- struct got_fileindex_diff_dir_cb *, void *);
+ struct got_pathlist_head *, const char *, const char *,
+ struct got_repository *, struct got_fileindex_diff_dir_cb *, void *);
static const struct got_error *
+read_dirlist(struct got_pathlist_head *dirlist, DIR *dir, const char *path)
+{
+ const struct got_error *err = NULL;
+ struct got_pathlist_entry *new = NULL;
+ struct dirent *dep = NULL;
+ struct dirent *de = NULL;
+
+ for (;;) {
+ de = malloc(sizeof(struct dirent) + NAME_MAX + 1);
+ if (de == NULL) {
+ err = got_error_from_errno("malloc");
+ break;
+ }
+
+ if (readdir_r(dir, de, &dep) != 0) {
+ err = got_error_from_errno("readdir_r");
+ free(de);
+ break;
+ }
+ if (dep == NULL) {
+ free(de);
+ break;
+ }
+
+ if (strcmp(de->d_name, ".") == 0 ||
+ strcmp(de->d_name, "..") == 0 ||
+ (path[0] == '\0' &&
+ strcmp(de->d_name, GOT_WORKTREE_GOT_DIR) == 0)) {
+ free(de);
+ continue;
+ }
+
+ err = got_pathlist_insert(&new, dirlist, de->d_name, de);
+ if (err) {
+ free(de);
+ break;
+ }
+ if (new == NULL) {
+ err = got_error(GOT_ERR_DIR_DUP_ENTRY);
+ free(de);
+ break;
+ }
+ }
+
+ return err;
+}
+
+void
+free_dirlist(struct got_pathlist_head *dirlist)
+{
+ struct got_pathlist_entry *dle;
+
+ TAILQ_FOREACH(dle, dirlist, entry)
+ free(dle->data);
+ got_pathlist_free(dirlist);
+}
+
+static const struct got_error *
walk_dir(struct got_pathlist_entry **next, struct got_fileindex *fileindex,
struct got_fileindex_entry **ie, struct got_pathlist_entry *dle,
const char *path, DIR *dir, const char *rootpath,
char *subpath;
char *subdirpath;
DIR *subdir;
+ struct got_pathlist_head subdirlist;
+ TAILQ_INIT(&subdirlist);
+
if (asprintf(&subpath, "%s%s%s", path,
path[0] == '\0' ? "" : "/", de->d_name) == -1)
return got_error_from_errno("asprintf");
return got_error_from_errno2("opendir", subdirpath);
}
- err = diff_fileindex_dir(fileindex, ie, subdir, rootpath,
- subpath, repo, cb, cb_arg);
+ err = read_dirlist(&subdirlist, subdir, subdirpath);
+ if (err) {
+ free(subpath);
+ free(subdirpath);
+ closedir(subdir);
+ return err;
+ }
+ err = diff_fileindex_dir(fileindex, ie, subdir, &subdirlist,
+ rootpath, subpath, repo, cb, cb_arg);
free(subpath);
free(subdirpath);
closedir(subdir);
+ free_dirlist(&subdirlist);
if (err)
return err;
}
static const struct got_error *
diff_fileindex_dir(struct got_fileindex *fileindex,
- struct got_fileindex_entry **ie, DIR *dir, const char *rootpath,
- const char *path, struct got_repository *repo,
- struct got_fileindex_diff_dir_cb *cb, void *cb_arg)
+ struct got_fileindex_entry **ie, DIR *dir,
+ struct got_pathlist_head *dirlist, const char *rootpath, const char *path,
+ struct got_repository *repo, struct got_fileindex_diff_dir_cb *cb,
+ void *cb_arg)
{
const struct got_error *err = NULL;
struct dirent *de = NULL;
size_t path_len = strlen(path);
- struct got_fileindex_entry *next;
- struct got_pathlist_head dirlist;
struct got_pathlist_entry *dle;
- TAILQ_INIT(&dirlist);
-
- for (;;) {
- struct got_pathlist_entry *new = NULL;
- struct dirent *dep = NULL;
-
- de = malloc(sizeof(struct dirent) + NAME_MAX + 1);
- if (de == NULL) {
- err = got_error_from_errno("malloc");
- goto done;
- }
-
- if (readdir_r(dir, de, &dep) != 0) {
- err = got_error_from_errno("readdir_r");
- free(de);
- goto done;
- }
- if (dep == NULL) {
- free(de);
- break;
- }
-
- if (strcmp(de->d_name, ".") == 0 ||
- strcmp(de->d_name, "..") == 0 ||
- (path[0] == '\0' &&
- strcmp(de->d_name, GOT_WORKTREE_GOT_DIR) == 0)) {
- free(de);
- continue;
- }
-
- err = got_pathlist_insert(&new, &dirlist, de->d_name, de);
- if (err) {
- free(de);
- goto done;
- }
- if (new == NULL) {
- err = got_error(GOT_ERR_DIR_DUP_ENTRY);
- free(de);
- goto done;
- }
- }
-
- dle = TAILQ_FIRST(&dirlist);
+ dle = TAILQ_FIRST(dirlist);
while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || dle) {
if (dle && *ie) {
char *de_path;
err = walk_dir(&dle, fileindex, ie, dle, path,
dir, rootpath, repo, cb, cb_arg);
} else if (cmp < 0 ) {
- next = walk_fileindex(fileindex, *ie);
err = cb->diff_old(cb_arg, *ie, path);
if (err)
break;
- *ie = next;
+ *ie = walk_fileindex(fileindex, *ie);
} else {
err = cb->diff_new(cb_arg, de, path);
if (err)
if (err)
break;
} else if (*ie) {
- next = walk_fileindex(fileindex, *ie);
err = cb->diff_old(cb_arg, *ie, path);
if (err)
break;
- *ie = next;
+ *ie = walk_fileindex(fileindex, *ie);
} else if (dle) {
de = dle->data;
err = cb->diff_new(cb_arg, de, path);
break;
}
}
-done:
- TAILQ_FOREACH(dle, &dirlist, entry)
- free(dle->data);
- got_pathlist_free(&dirlist);
+
return err;
}
const char *rootpath, const char *path, struct got_repository *repo,
struct got_fileindex_diff_dir_cb *cb, void *cb_arg)
{
- struct got_fileindex_entry *min;
- min = RB_MIN(got_fileindex_tree, &fileindex->entries);
- return diff_fileindex_dir(fileindex, &min, rootdir, rootpath, path,
- repo, cb, cb_arg);
+ const struct got_error *err;
+ struct got_fileindex_entry *ie;
+ struct got_pathlist_head dirlist;
+
+ TAILQ_INIT(&dirlist);
+ err = read_dirlist(&dirlist, rootdir, path);
+ if (err)
+ return err;
+ ie = RB_MIN(got_fileindex_tree, &fileindex->entries);
+ while (ie && !got_path_is_child(ie->path, path, strlen(path)))
+ ie = walk_fileindex(fileindex, ie);
+ err = diff_fileindex_dir(fileindex, &ie, rootdir, &dirlist, rootpath,
+ path, repo, cb, cb_arg);
+ free_dirlist(&dirlist);
+ return err;
}
RB_GENERATE(got_fileindex_tree, got_fileindex_entry, entry, got_fileindex_cmp);
blob - 80edb4d443d90485004348c8ef3b92fa6d592f6e
blob + 686a315559b212e3c9a0e54239e92de274a498b4
--- lib/worktree.c
+++ lib/worktree.c
if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
return got_error(GOT_ERR_CANCELLED);
- if (!got_path_is_child(parent_path, a->status_path, a->status_path_len))
+ if (!got_path_is_child(ie->path, a->status_path, a->status_path_len))
return NULL;
memcpy(blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
if (de->d_type == DT_LNK)
return NULL;
- if (!got_path_is_child(parent_path, a->status_path, a->status_path_len))
- return NULL;
-
if (parent_path[0]) {
if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
return got_error_from_errno("asprintf");
path = de->d_name;
}
- err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED, path,
- NULL, NULL);
+ if (got_path_is_child(path, a->status_path, a->status_path_len))
+ err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED,
+ path, NULL, NULL);
if (parent_path[0])
free(path);
return err;
blob - fa78fd826325bfbc31e69d96bf74d4329add0b6b
blob + caf49bac02e4804db8079107c17f7b157837f688
--- regress/cmdline/status.sh
+++ regress/cmdline/status.sh
test_done "$testroot" "$ret"
}
+function test_status_empty_dir {
+ local testroot=`test_init status_empty_dir`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ rm $testroot/wt/epsilon/zeta
+
+ echo '! epsilon/zeta' > $testroot/stdout.expected
+
+ (cd $testroot/wt && got status epsilon > $testroot/stdout)
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_status_empty_dir_unversioned_file {
+ local testroot=`test_init status_empty_dir_unversioned_file`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ rm $testroot/wt/epsilon/zeta
+ touch $testroot/wt/epsilon/unversioned
+
+ echo '? epsilon/unversioned' > $testroot/stdout.expected
+ echo '! epsilon/zeta' >> $testroot/stdout.expected
+
+ (cd $testroot/wt && got status epsilon > $testroot/stdout)
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_status_basic
run_test test_status_subdir_no_mods
run_test test_status_subdir_no_mods2
run_test test_status_ignores_symlink
run_test test_status_shows_no_mods_after_complete_merge
run_test test_status_shows_conflict
+run_test test_status_empty_dir
+run_test test_status_empty_dir_unversioned_file