[PATCH 1/5] Add 'df_name_compare()' helper function
- From
Linus Torvalds <torvalds@linux-foundation.org>
- Date
- Mar 6, 2008, 02:25 UTC
- Message-ID
- <b1cd18fa986c63bea6d0a20ac580b993e5fffaa2.1204777699.git.torvalds@linux-foundation.org>
- In-Reply-To
- <cover.1204777699.git.torvalds@linux-foundation.org>
This new helper is identical to base_name_compare(), except it compares conflicting directory/file entries as equal in order to help handling DF conflicts (thus the name).
Note that while a directory name compares as equal to a regular file with the new helper, they then individually compare _differently_ to a filename that has a dot after the basename (because '\0' < '.' < '/').
So a directory called "foo/" will compare equal to a file "foo", even though "foo.c" will compare after "foo" and before "foo/"
This will be used by routines that want to traverse the git namespace but then handle conflicting entries together when possible.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- cache.h | 1 + read-cache.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/cache.h b/cache.h index e230302..6eb16cb 100644 --- a/cache.h +++ b/cache.h @@ -536,6 +536,7 @@ extern int create_symref(const char *ref, const char *refs_heads_master, const c extern int validate_headref(const char *ref); extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); +extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2); extern void *read_object_with_reference(const unsigned char *sha1, diff --git a/read-cache.c b/read-cache.c index 657f0c5..bf649a3 100644 --- a/read-cache.c +++ b/read-cache.c @@ -351,6 +351,41 @@ int base_name_compare(const char *name1, int len1, int mode1, return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0; } +/* + * df_name_compare() is identical to base_name_compare(), except it + * compares conflicting directory/file entries as equal. Note that + * while a directory name compares as equal to a regular file, they + * then individually compare _differently_ to a filename that has + * a dot after the basename (because '\0' < '.' < '/'). + * + * This is used by routines that want to traverse the git namespace + * but then handle conflicting entries together when possible. + */ +int df_name_compare(const char *name1, int len1, int mode1, + const char *name2, int len2, int mode2) +{ + int len = len1 < len2 ? len1 : len2, cmp; + unsigned char c1, c2; + + cmp = memcmp(name1, name2, len); + if (cmp) + return cmp; + /* Directories and files compare equal (same length, same name) */ + if (len1 == len2) + return 0; + c1 = name1[len]; + if (!c1 && S_ISDIR(mode1)) + c1 = '/'; + c2 = name2[len]; + if (!c2 && S_ISDIR(mode2)) + c2 = '/'; + if (c1 == '/' && !c2) + return 0; + if (c2 == '/' && !c1) + return 0; + return c1 - c2; +} + int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2) { int len1 = flags1 & CE_NAMEMASK;
-- 1.5.4.3.452.g67136