Commit 61bef72dc35c593e632dc2008c4eec271a264869

Alan Rogers 2014-05-20T23:57:40

Start adding GIT_DELTA_UNREADABLE and GIT_STATUS_WT_UNREADABLE.

diff --git a/include/git2/diff.h b/include/git2/diff.h
index b40cc61..ebf47e3 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -191,6 +191,9 @@ typedef enum {
 	 *  can apply given diff information to binary files.
 	 */
 	GIT_DIFF_SHOW_BINARY = (1 << 30),
+	
+	/** Include unreadable files in the diff */
+	GIT_DIFF_INCLUDE_UNREADABLE = (1 << 31),
 } git_diff_option_t;
 
 /**
@@ -237,6 +240,7 @@ typedef enum {
 	GIT_DELTA_IGNORED = 6,    /** entry is ignored item in workdir */
 	GIT_DELTA_UNTRACKED = 7,  /** entry is untracked item in workdir */
 	GIT_DELTA_TYPECHANGE = 8, /** type of entry changed between old and new */
+	GIT_DELTA_UNREADABLE = 9, /** entry is unreadable */
 } git_delta_t;
 
 /**
diff --git a/include/git2/status.h b/include/git2/status.h
index effe5e1..794a629 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -43,6 +43,7 @@ typedef enum {
 	GIT_STATUS_WT_DELETED       = (1u << 9),
 	GIT_STATUS_WT_TYPECHANGE    = (1u << 10),
 	GIT_STATUS_WT_RENAMED       = (1u << 11),
+	GIT_STATUS_WT_UNREADABLE    = (1u << 12),
 
 	GIT_STATUS_IGNORED          = (1u << 14),
 } git_status_t;
diff --git a/src/checkout.c b/src/checkout.c
index 20763fd..1f793d4 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -116,6 +116,7 @@ static int checkout_notify(
 		case GIT_DELTA_ADDED:
 		case GIT_DELTA_IGNORED:
 		case GIT_DELTA_UNTRACKED:
+		case GIT_DELTA_UNREADABLE:
 			target = &delta->new_file;
 			break;
 		case GIT_DELTA_DELETED:
@@ -2063,6 +2064,7 @@ int git_checkout_iterator(
 
 	diff_opts.flags =
 		GIT_DIFF_INCLUDE_UNMODIFIED |
+		GIT_DIFF_INCLUDE_UNREADABLE |
 		GIT_DIFF_INCLUDE_UNTRACKED |
 		GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
 		GIT_DIFF_INCLUDE_IGNORED |
diff --git a/src/diff.c b/src/diff.c
index a0cfb58..32573a2 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -92,6 +92,10 @@ static int diff_delta__from_one(
 	if (status == GIT_DELTA_UNTRACKED &&
 		DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED))
 		return 0;
+	
+	if (status == GIT_DELTA_UNREADABLE &&
+		DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNREADABLE))
+		return 0;
 
 	if (!git_pathspec__match(
 			&diff->pathspec, entry->path,
@@ -201,6 +205,11 @@ static git_diff_delta *diff_delta__last_for_item(
 			git_oid__cmp(&delta->new_file.id, &item->id) == 0)
 			return delta;
 		break;
+	case GIT_DELTA_UNREADABLE:
+		if (diff->strcomp(delta->new_file.path, item->path) == 0 &&
+			git_oid__cmp(&delta->new_file.id, &item->id) == 0)
+			return delta;
+		break;
 	case GIT_DELTA_MODIFIED:
 		if (git_oid__cmp(&delta->old_file.id, &item->id) == 0 ||
 			git_oid__cmp(&delta->new_file.id, &item->id) == 0)
@@ -293,6 +302,10 @@ bool git_diff_delta__should_skip(
 		(flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
 		return true;
 
+	if (delta->status == GIT_DELTA_UNREADABLE &&
+		(flags & GIT_DIFF_INCLUDE_UNREADABLE) == 0)
+		return true;
+
 	return false;
 }
 
@@ -924,17 +937,22 @@ static int handle_unmatched_new_item(
 		if (recurse_into_dir) {
 			error = git_iterator_advance_into(&info->nitem, info->new_iter);
 
-			/* if real error or no error, proceed with iteration */
-			if (error != GIT_ENOTFOUND && error != GIT_EUNREADABLE)
-				return error;
-			giterr_clear();
+			printf("error advancing into diff %d\n", error);
+			if (error == GIT_EUNREADABLE) {
+				delta_type = GIT_DELTA_UNREADABLE;
+			} else {
+				/* if real error or no error, proceed with iteration */
+				if (error != GIT_ENOTFOUND)
+					return error;
+				giterr_clear();
 
-			/* if directory is empty, can't advance into it, so either skip
-			 * it or ignore it
-			 */
-			if (contains_oitem && error != GIT_EUNREADABLE)
-				return git_iterator_advance(&info->nitem, info->new_iter);
-			delta_type = GIT_DELTA_IGNORED;
+				/* if directory is empty, can't advance into it, so either skip
+				 * it or ignore it
+				 */
+				if (contains_oitem )
+					return git_iterator_advance(&info->nitem, info->new_iter);
+				delta_type = GIT_DELTA_IGNORED;
+			}
 		}
 	}
 
diff --git a/src/diff_file.c b/src/diff_file.c
index f2a1d50..96be094 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -112,6 +112,7 @@ int git_diff_file_content__init_from_diff(
 		has_data = !use_old &&
 			(diff->opts.flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) != 0;
 		break;
+	case GIT_DELTA_UNREADABLE:
 	case GIT_DELTA_MODIFIED:
 	case GIT_DELTA_COPIED:
 	case GIT_DELTA_RENAMED:
diff --git a/src/diff_print.c b/src/diff_print.c
index 08e1e7f..964c495 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -82,14 +82,15 @@ char git_diff_status_char(git_delta_t status)
 	char code;
 
 	switch (status) {
-	case GIT_DELTA_ADDED:     code = 'A'; break;
-	case GIT_DELTA_DELETED:   code = 'D'; break;
-	case GIT_DELTA_MODIFIED:  code = 'M'; break;
-	case GIT_DELTA_RENAMED:   code = 'R'; break;
-	case GIT_DELTA_COPIED:    code = 'C'; break;
-	case GIT_DELTA_IGNORED:   code = 'I'; break;
-	case GIT_DELTA_UNTRACKED: code = '?'; break;
-	default:                  code = ' '; break;
+		case GIT_DELTA_ADDED:      code = 'A'; break;
+		case GIT_DELTA_DELETED:    code = 'D'; break;
+		case GIT_DELTA_MODIFIED:   code = 'M'; break;
+		case GIT_DELTA_RENAMED:    code = 'R'; break;
+		case GIT_DELTA_COPIED:     code = 'C'; break;
+		case GIT_DELTA_IGNORED:    code = 'I'; break;
+		case GIT_DELTA_UNTRACKED:  code = '?'; break;
+		case GIT_DELTA_UNREADABLE: code = 'X'; break;
+		default:                   code = ' '; break;
 	}
 
 	return code;
@@ -414,6 +415,7 @@ static int diff_print_patch_file(
 	if (S_ISDIR(delta->new_file.mode) ||
 		delta->status == GIT_DELTA_UNMODIFIED ||
 		delta->status == GIT_DELTA_IGNORED ||
+		delta->status == GIT_DELTA_UNREADABLE ||
 		(delta->status == GIT_DELTA_UNTRACKED &&
 		 (pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0))
 		return 0;
diff --git a/src/diff_tform.c b/src/diff_tform.c
index a2dab0a..423a0ca 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -114,7 +114,7 @@ static git_diff_delta *diff_delta__merge_like_cgit_reversed(
 	if ((dup = diff_delta__dup(a, pool)) == NULL)
 		return NULL;
 
-	if (b->status == GIT_DELTA_UNMODIFIED || b->status == GIT_DELTA_UNTRACKED)
+	if (b->status == GIT_DELTA_UNMODIFIED || b->status == GIT_DELTA_UNTRACKED || b->status == GIT_DELTA_UNREADABLE)
 		return dup;
 
 	if (dup->status == GIT_DELTA_DELETED) {
@@ -732,6 +732,7 @@ static bool is_rename_source(
 	switch (delta->status) {
 	case GIT_DELTA_ADDED:
 	case GIT_DELTA_UNTRACKED:
+	case GIT_DELTA_UNREADABLE:
 	case GIT_DELTA_IGNORED:
 		return false;
 
@@ -786,6 +787,7 @@ GIT_INLINE(bool) delta_is_new_only(git_diff_delta *delta)
 {
 	return (delta->status == GIT_DELTA_ADDED ||
 			delta->status == GIT_DELTA_UNTRACKED ||
+			delta->status == GIT_DELTA_UNREADABLE ||
 			delta->status == GIT_DELTA_IGNORED);
 }
 
diff --git a/src/status.c b/src/status.c
index 061c9d5..6b80098 100644
--- a/src/status.c
+++ b/src/status.c
@@ -62,6 +62,9 @@ static unsigned int workdir_delta2status(
 	case GIT_DELTA_UNTRACKED:
 		st = GIT_STATUS_WT_NEW;
 		break;
+	case GIT_DELTA_UNREADABLE:
+		st = GIT_STATUS_WT_UNREADABLE;
+		break;
 	case GIT_DELTA_DELETED:
 		st = GIT_STATUS_WT_DELETED;
 		break;