[PATCH RFC v2 2/4] cache: Added ce_norm_sha1() and related cache_entry fields.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The index now keeps track of the conversion mode that was active
when the entry was created. This can be used to detect the most
common cases of when the conversion mode has changed.

Signed-off-by: Henrik Grubbström <grubba@xxxxxxxxxx>
---
git_norm_flags has been extended with one flag (NORM_CONV_CRLF_WT)
to be able to keep track of the working tree state as well as the
repository state.

git_norm_flags() now takes account of the auto_crlf state.

ce_match_stat_basic() now knows that a normalization change may
affect the working tree file size.

Updating of the normalization state is now done in ce_compare_data().

 cache.h      |   14 ++++++++++++++
 convert.c    |   31 +++++++++++++++++++++++++++++++
 read-cache.c |   17 +++++++++++++++--
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/cache.h b/cache.h
index 1fe2d7d..3e70bef 100644
--- a/cache.h
+++ b/cache.h
@@ -151,10 +151,18 @@ struct cache_entry {
 	unsigned int ce_size;
 	unsigned int ce_flags;
 	unsigned char sha1[20];
+	unsigned int norm_flags;
+	unsigned char norm_sha1[20];
 	struct cache_entry *next;
 	char name[FLEX_ARRAY]; /* more */
 };
 
+#define NORM_CONV_CRLF_GIT	0x0001
+#define NORM_CONV_CRLF_WT	0x0002
+#define NORM_CONV_CRLF_GUESS	0x0004
+#define NORM_CONV_IDENT		0x0008
+#define NORM_CONV_FILT		0x0010
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_EXTENDED  (0x4000)
@@ -278,6 +286,11 @@ static inline int ce_to_dtype(const struct cache_entry *ce)
 	else
 		return DT_UNKNOWN;
 }
+static inline unsigned char *ce_norm_sha1(struct cache_entry *ce)
+{
+	return ce->norm_flags?ce->norm_sha1:ce->sha1;
+}
+
 #define canon_mode(mode) \
 	(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
 	S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
@@ -1014,6 +1027,7 @@ extern void trace_argv_printf(const char **argv, const char *format, ...);
 
 /* convert.c */
 /* returns 1 if *dst was used */
+extern unsigned int git_norm_flags(const char *path);
 extern int convert_to_git(const char *path, const char *src, size_t len,
                           struct strbuf *dst, enum safe_crlf checksafe);
 extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
diff --git a/convert.c b/convert.c
index 4f8fcb7..5f36669 100644
--- a/convert.c
+++ b/convert.c
@@ -568,6 +568,37 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
 	return !!ATTR_TRUE(value);
 }
 
+unsigned int git_norm_flags(const char *path)
+{
+	struct git_attr_check check[3];
+	int crlf = CRLF_GUESS;
+	int ident = 0;
+	unsigned ret = 0;
+	struct convert_driver *drv = NULL;
+
+	setup_convert_check(check);
+	if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
+		crlf = git_path_check_crlf(path, check + 0);
+		ident = git_path_check_ident(path, check + 1);
+		drv = git_path_check_convert(path, check + 2);
+	}
+
+	if (auto_crlf && (crlf != CRLF_BINARY)) {
+		ret |= NORM_CONV_CRLF_GIT;
+		if (crlf != CRLF_INPUT && auto_crlf > 0)
+			ret |= NORM_CONV_CRLF_WT;
+		if (crlf == CRLF_GUESS)
+			ret |= NORM_CONV_CRLF_GUESS;
+	}
+	if (ident) {
+		ret |= NORM_CONV_IDENT;
+	}
+	if (drv) {
+		ret |= NORM_CONV_FILT;
+	}
+	return ret;
+}
+
 int convert_to_git(const char *path, const char *src, size_t len,
                    struct strbuf *dst, enum safe_crlf checksafe)
 {
diff --git a/read-cache.c b/read-cache.c
index f1f789b..1a698bf 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -88,12 +88,20 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 static int ce_compare_data(struct cache_entry *ce, struct stat *st)
 {
 	int match = -1;
-	int fd = open(ce->name, O_RDONLY);
+	int fd;
+	unsigned int norm_flags = git_norm_flags(ce->name);
 
+	if (norm_flags != ce->norm_flags) {
+		ce->norm_flags = norm_flags;
+		if (norm_flags)
+			index_blob(ce->norm_sha1, ce->sha1, 0, ce->name);
+	}
+
+	fd = open(ce->name, O_RDONLY);
 	if (fd >= 0) {
 		unsigned char sha1[20];
 		if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
-			match = hashcmp(sha1, ce->sha1);
+			match = hashcmp(sha1, ce_norm_sha1(ce));
 		/* index_fd() closed the file descriptor already */
 	}
 	return match;
@@ -227,6 +235,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 		changed |= INODE_CHANGED;
 #endif
 
+	/* ce_size can not be trusted if the conversion mode has changed. */
+	if ((ce->ce_mode & S_IFMT) == S_IFREG &&
+	    ce->norm_flags != git_norm_flags(ce->name))
+		return changed;
+
 	if (ce->ce_size != (unsigned int) st->st_size)
 		changed |= DATA_CHANGED;
 
-- 
1.7.0.4.369.g81e89

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]