From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/VX/gq/SHA256E-s5263957--977af1c7373ecbca2f2df44e782afb143e71a38b0af965f02cd1178ab5b82b4e.gz/SHA256E-s5263957--977af1c7373ecbca2f2df44e782afb143e71a38b0af965f02cd1178ab5b82b4e.gz
Return-Path: <joey@kitenet.net>
X-Original-To: joeyh@joeyh.name
Delivered-To: joey@kitenet.net
X-Question: 42
Authentication-Results: kitenet.net;
	dkim=pass (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=ier2ZdRe;
	dkim-atps=neutral
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277197; bh=kOlU+hQ5LyTEz/eutsD10qEeMefFCuV9/88MgBjyH3k=;
	h=From:To:Cc:Subject:Date:From;
	b=ier2ZdReiz3+8cyLyfBhIuFH0zribYdza324RRso423MVVwX5Z5dXjkqHvfVpRxVA
	 SLJCxSfGmOuiiQikb4CcFpmTi8rt+gcLqcgvQGgQMug+ee8CysZVHW76EpSILa8eIN
	 1qIOb5q8Q8fHMaRifEWQvbQiw4XTzTdDJZdyPMIE=
From: Joey Hess <joeyh@joeyh.name>
To: git@vger.kernel.org
Cc: Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 0/8] extend smudge/clean filters with direct file access (for pu)
Date: Mon, 11 Jul 2016 18:45:04 -0400
Message-Id: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
X-Spam-Status: No, score=-95.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,
	DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_BLOCKED,RCVD_IN_PBL,
	RCVD_IN_SORBS_DUL,RDNS_DYNAMIC,SPF_SOFTFAIL,URIBL_BLOCKED,USER_IN_WHITELIST
	autolearn=no autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Content-Length: 1441
Lines: 40

Back from vacation with a reroll of jh/clean-smudge-annex.

Deals with conflicting changes from cc/apply-am in pu.

Since tb/convert-peek-in-index is not currently in pu, this reroll isn't
based on it, and will conflict if that topic gets added back into pu.
Not sure what the status of tb/convert-peek-in-index is at this point?

Improvements from Junio's review:

	fix build with DEVELOPER=1
	style fixes
	use test_cmp in test cases
	improve robustness of a test case
	clean up some confusing code
	small performance tweak

Joey Hess (8):
  clarify %f documentation
  add smudgeToFile and cleanFromFile filter configs
  use cleanFromFile in git add
  use smudgeToFile in git checkout etc
  warn on unusable smudgeToFile/cleanFromFile config
  better recovery from failure of smudgeToFile filter
  use smudgeToFile filter in git am
  use smudgeToFile filter in recursive merge

 Documentation/config.txt        |  18 ++++-
 Documentation/gitattributes.txt |  42 ++++++++++++
 apply.c                         |  16 +++++
 convert.c                       | 148 ++++++++++++++++++++++++++++++++++++----
 convert.h                       |  10 +++
 entry.c                         |  59 ++++++++++++----
 merge-recursive.c               |  53 +++++++++++---
 sha1_file.c                     |  42 ++++++++++--
 t/t0021-conversion.sh           | 117 +++++++++++++++++++++++++++++++
 9 files changed, 459 insertions(+), 46 deletions(-)

-- 
2.8.1

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id B1F5B1C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:46:53 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=hbTM55ad;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752420AbcGKWqv (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:46:51 -0400
Received: from kitenet.net ([66.228.36.95]:60934 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751854AbcGKWqu (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:46:50 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277197; bh=Q37/p1l59xZISgA1LWyXTUqwJEg7T96CGx2mCEyU9UM=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=hbTM55adTxAE7hwBgj9q7PkR66nfsMxhWSpQn/R9iSUOaJ11fW10rEUxkLzcXKK5x
	 ktVQ6sdgyCC5CbgYfBn6sMJ+EH6sTTJlLS0czzSkl453Izvk85rBtBGYsVSCzgbPai
	 1rM45vbD/pViJQ2IUyiT/WxLexQFFn0DnVLiWuWA=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 1/8] clarify %f documentation
Date:	Mon, 11 Jul 2016 18:45:05 -0400
Message-Id: <1468277112-9909-2-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 1148
Lines: 31

It's natural to expect %f to be an actual file on disk; help avoid that
mistake.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 Documentation/gitattributes.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index f2afdb6..197ece8 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -379,6 +379,11 @@ substitution.  For example:
 	smudge = git-p4-filter --smudge %f
 ------------------------
 
+Note that "%f" is the name of the path that is being worked on. Depending
+on the version that is being filtered, the corresponding file on disk may
+not exist, or may have different contents. So, smudge and clean commands
+should not try to access the file on disk, but only act as filters on the
+content provided to them on standard input.
 
 Interaction between checkin/checkout attributes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 04F251C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:07 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=NOnwhtEt;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752532AbcGKWrD (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:03 -0400
Received: from kitenet.net ([66.228.36.95]:60970 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752439AbcGKWrA (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:00 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=NRbzz9lX+l0UUh9pAD1CQEaHhmhOg2qk05TuAMiBsPo=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=NOnwhtEtJu+wBwiPrABDPIiic0tTHORjOkouxfQbD+rgbTjsY2mKzfmOsW0JdL5c9
	 UyIeOOTmDA8jFAvt/o/9Yj7P39nbgg7fjX/tS8xd5oYSRV15Vg0ePEZ98nSHu+KjOR
	 q06IOF8YyqtTAz4S3lSXXlNFfpqrFw8bQT4Xhq6Y=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 2/8] add smudgeToFile and cleanFromFile filter configs
Date:	Mon, 11 Jul 2016 18:45:06 -0400
Message-Id: <1468277112-9909-3-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 13634
Lines: 374

This adds new smudgeToFile and cleanFromFile filter commands,
which are similar to smudge and clean but allow direct access to files on
disk.

This interface can be much more efficient when operating on large files,
because the whole file content does not need to be streamed through the
filter. It even allows for things like cleanFromFile commands that avoid
reading the whole content of the file, and for smudgeToFile commands that
populate a work tree file using an efficient Copy On Write operation.

The new filter commands will not be used for all filtering. They are
efficient to use when git add is adding a file, or when the work tree is
being updated, but not a good fit when git is internally filtering blob
objects in memory for eg, a diff.

So, a user who wants to use smudgeToFile should also provide a smudge
command to be used in cases where smudgeToFile is not used. And ditto
with cleanFromFile and clean. To avoid foot-shooting configurations, the
new commands are not used unless the old commands are also configured.

That also ensures that a filter driver configuration that includes these
new commands will work, although less efficiently, when used with an older
version of git that does not support them.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 Documentation/config.txt        |  18 ++++++-
 Documentation/gitattributes.txt |  37 ++++++++++++++
 convert.c                       | 111 +++++++++++++++++++++++++++++++++++-----
 convert.h                       |  10 ++++
 4 files changed, 160 insertions(+), 16 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 19493aa..a55bed8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1325,15 +1325,29 @@ format.useAutoBase::
 	format-patch by default.
 
 filter.<driver>.clean::
-	The command which is used to convert the content of a worktree
+	The command which is used as a filter to convert the content of a worktree
 	file to a blob upon checkin.  See linkgit:gitattributes[5] for
 	details.
 
 filter.<driver>.smudge::
-	The command which is used to convert the content of a blob
+	The command which is used as a filter to convert the content of a blob
 	object to a worktree file upon checkout.  See
 	linkgit:gitattributes[5] for details.
 
+filter.<driver>.cleanFromFile::
+	Similar to filter.<driver>.clean but the specified command
+	directly accesses a worktree file on disk, rather than
+	receiving the file content from standard input.
+	Only used when filter.<driver>.clean is also configured.
+	See linkgit:gitattributes[5] for details.
+
+filter.<driver>.smudgeToFile::
+	Similar to filter.<driver>.smudge but the specified command
+	writes the content of a blob directly to a worktree file,
+	rather than to standard output.
+	Only used when filter.<driver>.smudge is also configured.
+	See linkgit:gitattributes[5] for details.
+
 fsck.<msg-id>::
 	Allows overriding the message type (error, warn or ignore) of a
 	specific message ID such as `missingEmail`.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 197ece8..a58aafc 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -385,6 +385,43 @@ not exist, or may have different contents. So, smudge and clean commands
 should not try to access the file on disk, but only act as filters on the
 content provided to them on standard input.
 
+There are two extra commands "cleanFromFile" and "smudgeToFile", which
+can optionally be set in a filter driver. These are similar to the "clean"
+and "smudge" commands, but avoid needing to pipe the contents of files
+through the filters, and instead read/write files in the filesystem.
+This can be more efficient when using filters with large files that are not
+directly stored in the repository.
+
+Both "cleanFromFile" and "smudgeToFile" are provided a path as an
+added parameter after the configured command line.
+
+The "cleanFromFile" command is provided the path to the file that
+it should clean. Like the "clean" command, it should output the cleaned
+version to standard output.
+
+The "smudgeToFile" command is provided a path to the file that it
+should write to. (This file will already exist, as an empty file that can
+be written to or replaced.) Like the "smudge" command, "smudgeToFile"
+is fed the blob object from its standard input.
+
+Some git operations that need to apply filters cannot use "cleanFromFile"
+and "smudgeToFile", since the files are not present to disk. So, to avoid
+inconsistent behavior, "cleanFromFile" will only be used if "clean" is
+also configured, and "smudgeToFile" will only be used if "smudge" is also
+configured.
+
+An example large file storage filter driver using cleanFromFile and
+smudgeToFile follows:
+
+------------------------
+[filter "bigfiles"]
+	clean = store-bigfile --from-stdin
+	cleanFromFile = store-bigfile --from-file
+	smudge = retrieve-bigfile --to-stdout
+	smudgeToFile = retrieve-bigfile --to-file
+	required
+------------------------
+
 Interaction between checkin/checkout attributes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/convert.c b/convert.c
index 214c99f..eb7774f 100644
--- a/convert.c
+++ b/convert.c
@@ -358,7 +358,8 @@ struct filter_params {
 	unsigned long size;
 	int fd;
 	const char *cmd;
-	const char *path;
+	const char *path; /* Path within the git repository */
+	const char *fspath; /* Path to file on disk */
 };
 
 static int filter_buffer_or_fd(int in, int out, void *data)
@@ -387,6 +388,15 @@ static int filter_buffer_or_fd(int in, int out, void *data)
 	strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
 	strbuf_release(&path);
 
+	/* append fspath to the command if it's set, separated with a space */
+	if (params->fspath) {
+		struct strbuf fspath = STRBUF_INIT;
+		sq_quote_buf(&fspath, params->fspath);
+		strbuf_addstr(&cmd, " ");
+		strbuf_addbuf(&cmd, &fspath);
+		strbuf_release(&fspath);
+	}
+
 	argv[0] = cmd.buf;
 
 	child_process.argv = argv;
@@ -425,7 +435,8 @@ static int filter_buffer_or_fd(int in, int out, void *data)
 	return (write_err || status);
 }
 
-static int apply_filter(const char *path, const char *src, size_t len, int fd,
+static int apply_filter(const char *path, const char *fspath,
+			const char *src, size_t len, int fd,
                         struct strbuf *dst, const char *cmd)
 {
 	/*
@@ -454,6 +465,7 @@ static int apply_filter(const char *path, const char *src, size_t len, int fd,
 	params.fd = fd;
 	params.cmd = cmd;
 	params.path = path;
+	params.fspath = fspath;
 
 	fflush(NULL);
 	if (start_async(&async))
@@ -484,6 +496,8 @@ static struct convert_driver {
 	struct convert_driver *next;
 	const char *smudge;
 	const char *clean;
+	const char *smudge_to_file;
+	const char *clean_from_file;
 	int required;
 } *user_convert, **user_convert_tail;
 
@@ -510,8 +524,9 @@ static int read_convert_config(const char *var, const char *value, void *cb)
 	}
 
 	/*
-	 * filter.<name>.smudge and filter.<name>.clean specifies
-	 * the command line:
+	 * filter.<name>.smudge, filter.<name>.clean,
+	 * filter.<name>.smudgeToFile, filter.<name>.cleanFromFile
+	 * specifies the command line:
 	 *
 	 *	command-line
 	 *
@@ -524,6 +539,12 @@ static int read_convert_config(const char *var, const char *value, void *cb)
 	if (!strcmp("clean", key))
 		return git_config_string(&drv->clean, var, value);
 
+	if (!strcmp("smudgetofile", key))
+		return git_config_string(&drv->smudge_to_file, var, value);
+
+	if (!strcmp("cleanfromfile", key))
+		return git_config_string(&drv->clean_from_file, var, value);
+
 	if (!strcmp("required", key)) {
 		drv->required = git_config_bool(var, value);
 		return 0;
@@ -821,7 +842,37 @@ int would_convert_to_git_filter_fd(const char *path)
 	if (!ca.drv->required)
 		return 0;
 
-	return apply_filter(path, NULL, 0, -1, NULL, ca.drv->clean);
+	return apply_filter(path, NULL, NULL, 0, -1, NULL, ca.drv->clean);
+}
+
+int can_clean_from_file(const char *path)
+{
+	struct conv_attrs ca;
+
+	convert_attrs(&ca, path);
+	if (!ca.drv)
+		return 0;
+
+	/*
+	 * Only use the cleanFromFile filter when the clean filter is also
+	 * configured.
+	 */
+	return (ca.drv->clean_from_file && ca.drv->clean);
+}
+
+int can_smudge_to_file(const char *path)
+{
+	struct conv_attrs ca;
+
+	convert_attrs(&ca, path);
+	if (!ca.drv)
+		return 0;
+
+	/*
+	 * Only use the smudgeToFile filter when the smudge filter is also
+	 * configured.
+	 */
+	return (ca.drv->smudge_to_file && ca.drv->smudge);
 }
 
 const char *get_convert_attr_ascii(const char *path)
@@ -864,7 +915,7 @@ int convert_to_git(const char *path, const char *src, size_t len,
 		required = ca.drv->required;
 	}
 
-	ret |= apply_filter(path, src, len, -1, dst, filter);
+	ret |= apply_filter(path, NULL, src, len, -1, dst, filter);
 	if (!ret && required)
 		die("%s: clean filter '%s' failed", path, ca.drv->name);
 
@@ -889,14 +940,34 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,
 	assert(ca.drv);
 	assert(ca.drv->clean);
 
-	if (!apply_filter(path, NULL, 0, fd, dst, ca.drv->clean))
+	if (!apply_filter(path, NULL, NULL, 0, fd, dst, ca.drv->clean))
 		die("%s: clean filter '%s' failed", path, ca.drv->name);
 
 	crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
 	ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
 }
 
-static int convert_to_working_tree_internal(const char *path, const char *src,
+void convert_to_git_filter_from_file(const char *path, struct strbuf *dst,
+				   enum safe_crlf checksafe)
+{
+	struct conv_attrs ca;
+	convert_attrs(&ca, path);
+
+	assert(ca.drv);
+	assert(ca.drv->clean);
+	assert(ca.drv->clean_from_file);
+
+	if (!apply_filter(path, path, "", 0, -1, dst, ca.drv->clean_from_file))
+		die("%s: cleanFromFile filter '%s' failed", path, ca.drv->name);
+
+	crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action,
+		checksafe);
+	ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
+}
+
+static int convert_to_working_tree_internal(const char *path,
+					    const char *destpath,
+					    const char *src,
 					    size_t len, struct strbuf *dst,
 					    int normalizing)
 {
@@ -907,7 +978,10 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
 
 	convert_attrs(&ca, path);
 	if (ca.drv) {
-		filter = ca.drv->smudge;
+		if (destpath)
+			filter = ca.drv->smudge_to_file;
+		else
+			filter = ca.drv->smudge;
 		required = ca.drv->required;
 	}
 
@@ -918,7 +992,7 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
 	}
 	/*
 	 * CRLF conversion can be skipped if normalizing, unless there
-	 * is a smudge filter.  The filter might expect CRLFs.
+	 * is a filter.  The filter might expect CRLFs.
 	 */
 	if (filter || !normalizing) {
 		ret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action);
@@ -928,21 +1002,30 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
 		}
 	}
 
-	ret_filter = apply_filter(path, src, len, -1, dst, filter);
+	ret_filter = apply_filter(path, destpath, src, len, -1, dst, filter);
 	if (!ret_filter && required)
-		die("%s: smudge filter %s failed", path, ca.drv->name);
+		die("%s: %s filter %s failed", path, destpath ? "smudgeToFile" : "smudge", ca.drv->name);
 
 	return ret | ret_filter;
 }
 
 int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
 {
-	return convert_to_working_tree_internal(path, src, len, dst, 0);
+	return convert_to_working_tree_internal(path, NULL, src, len, dst, 0);
+}
+
+int convert_to_working_tree_filter_to_file(const char *path, const char *destpath, const char *src, size_t len)
+{
+	struct strbuf output = STRBUF_INIT;
+	int ret = convert_to_working_tree_internal(path, destpath, src, len, &output, 0);
+	/* The smudgeToFile filter stdout is not used. */
+	strbuf_release(&output);
+	return ret;
 }
 
 int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
 {
-	int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
+	int ret = convert_to_working_tree_internal(path, NULL, src, len, dst, 1);
 	if (ret) {
 		src = dst->buf;
 		len = dst->len;
diff --git a/convert.h b/convert.h
index 82871a1..6f46d10 100644
--- a/convert.h
+++ b/convert.h
@@ -42,6 +42,10 @@ 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);
+extern int convert_to_working_tree_filter_to_file(const char *path,
+						  const char *destpath,
+						  const char *src,
+						  size_t len);
 extern int renormalize_buffer(const char *path, const char *src, size_t len,
 			      struct strbuf *dst);
 static inline int would_convert_to_git(const char *path)
@@ -53,6 +57,12 @@ extern void convert_to_git_filter_fd(const char *path, int fd,
 				     struct strbuf *dst,
 				     enum safe_crlf checksafe);
 extern int would_convert_to_git_filter_fd(const char *path);
+/* Precondition: can_clean_from_file(path) == true */
+extern void convert_to_git_filter_from_file(const char *path,
+					    struct strbuf *dst,
+					    enum safe_crlf checksafe);
+extern int can_clean_from_file(const char *path);
+extern int can_smudge_to_file(const char *path);
 
 /*****************************************************************
  *
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 92F4B1C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:02 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=O21fZnmu;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752507AbcGKWq7 (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:46:59 -0400
Received: from kitenet.net ([66.228.36.95]:60948 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752439AbcGKWq6 (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:46:58 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277197; bh=ID7Cvl2BMx/TZGvnWWIJ3y9tfZmZmZ0hcgqOsxLVm9Q=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=O21fZnmuEK0afkVNZdA2KL+bhF+skap1V8rdhqtR0vzDPg7cri/BlGPK8eY5G/xi6
	 7f7vYgrq3QCN/0Q7cXsHSm0k8sgA2DLnriNR0Ga/gtk6OjqDr2JNHEMDoEt6MMyVto
	 4wAJLa+dzSUA8Y+8bwZ760DVTucDOLRoEINUvJ0Y=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 3/8] use cleanFromFile in git add
Date:	Mon, 11 Jul 2016 18:45:07 -0400
Message-Id: <1468277112-9909-4-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 3641
Lines: 127

Includes test cases.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 sha1_file.c           | 42 ++++++++++++++++++++++++++++++++++++------
 t/t0021-conversion.sh | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 6 deletions(-)

diff --git a/sha1_file.c b/sha1_file.c
index 2fc22b0..549a20f 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -3335,6 +3335,29 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,
 	return ret;
 }
 
+static int index_from_file_convert_blob(unsigned char *sha1,
+				      const char *path, unsigned flags)
+{
+	int ret;
+	const int write_object = flags & HASH_WRITE_OBJECT;
+	struct strbuf sbuf = STRBUF_INIT;
+
+	assert(path);
+	assert(can_clean_from_file(path));
+
+	convert_to_git_filter_from_file(path, &sbuf,
+				 write_object ? safe_crlf : SAFE_CRLF_FALSE);
+
+	if (write_object)
+		ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+				      sha1);
+	else
+		ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+				     sha1);
+	strbuf_release(&sbuf);
+	return ret;
+}
+
 static int index_pipe(unsigned char *sha1, int fd, enum object_type type,
 		      const char *path, unsigned flags)
 {
@@ -3427,12 +3450,19 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned
 
 	switch (st->st_mode & S_IFMT) {
 	case S_IFREG:
-		fd = open(path, O_RDONLY);
-		if (fd < 0)
-			return error_errno("open(\"%s\")", path);
-		if (index_fd(sha1, fd, st, OBJ_BLOB, path, flags) < 0)
-			return error("%s: failed to insert into database",
-				     path);
+		if (can_clean_from_file(path)) {
+			if (index_from_file_convert_blob(sha1, path, flags) < 0)
+				return error("%s: failed to insert into database",
+					     path);
+		}
+		else {
+			fd = open(path, O_RDONLY);
+			if (fd < 0)
+				return error_errno("open(\"%s\")", path);
+			if (index_fd(sha1, fd, st, OBJ_BLOB, path, flags) < 0)
+				return error("%s: failed to insert into database",
+					     path);
+		}
 		break;
 	case S_IFLNK:
 		if (strbuf_readlink(&sb, path, st->st_size))
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 7bac2bc..bd84b80 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -12,6 +12,14 @@ tr \
 EOF
 chmod +x rot13.sh
 
+cat <<EOF >rot13-from-file.sh
+#!$SHELL_PATH
+fsfile="\$1"
+touch rot13-from-file.ran
+cat "\$fsfile" | ./rot13.sh
+EOF
+chmod +x rot13-from-file.sh
+
 test_expect_success setup '
 	git config filter.rot13.smudge ./rot13.sh &&
 	git config filter.rot13.clean ./rot13.sh &&
@@ -268,4 +276,32 @@ test_expect_success 'disable filter with empty override' '
 	test_must_be_empty err
 '
 
+test_expect_success 'cleanFromFile filter is used when adding a file' '
+	test_config filter.rot13.cleanFromFile ./rot13-from-file.sh &&
+
+	echo "*.t filter=rot13" >.gitattributes &&
+
+	cat test >fstest.t &&
+	git add fstest.t &&
+	test -e rot13-from-file.ran &&
+	rm -f rot13-from-file.ran &&
+
+	rm -f fstest.t &&
+	git checkout -- fstest.t &&
+	test_cmp test fstest.t
+'
+
+test_expect_success 'cleanFromFile filter is not used when clean filter is not configured' '
+	test_config filter.noclean.smudge ./rot13.sh &&
+	test_config filter.noclean.cleanFromFile ./rot13-from-file.sh &&
+
+	echo "*.no filter=noclean" >.gitattributes &&
+
+	cat test >test.no &&
+	git add test.no &&
+	test ! -e rot13-from-file.ran &&
+	git cat-file blob :test.no >actual &&
+	test_cmp test actual
+'
+
 test_done
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 363761C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:18 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=P+WpFgpS;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752612AbcGKWrO (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:14 -0400
Received: from kitenet.net ([66.228.36.95]:32768 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752439AbcGKWrN (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:13 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=tAWpo3wY2ayI3N2P5PIoaKI4XKz6M0EPI7WSh1kSoZc=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=P+WpFgpSST+oHI+yvWOFavctP60LP4dRf0CJA1N75Wk/pQIHue3j4sxVPNsjTAuj6
	 IzUxRBE2Ilz3E0UF3r6iL2lCVMtITzMvvTqYjr9xEXi8mGgInDOWD1bi7bdmt2NY1z
	 ZlAIY9kjZhF+1jmpxhc1YP+tkocCMOsmT/DbiGRI=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 4/8] use smudgeToFile in git checkout etc
Date:	Mon, 11 Jul 2016 18:45:08 -0400
Message-Id: <1468277112-9909-5-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 4367
Lines: 147

This makes git checkout, git reset, etc use smudgeToFile.

Includes test cases.

(There's a call to convert_to_working_tree in merge-recursive.c
that could also be made to use smudgeToFile as well.)

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 entry.c               | 40 ++++++++++++++++++++++++++++++++--------
 t/t0021-conversion.sh | 34 ++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/entry.c b/entry.c
index 519e042..81d12a1 100644
--- a/entry.c
+++ b/entry.c
@@ -146,6 +146,7 @@ static int write_entry(struct cache_entry *ce,
 	unsigned long size;
 	size_t wrote, newsize = 0;
 	struct stat st;
+	int regular_file, smudge_to_file;
 
 	if (ce_mode_s_ifmt == S_IFREG) {
 		struct stream_filter *filter = get_stream_filter(ce->name, ce->sha1);
@@ -175,8 +176,13 @@ static int write_entry(struct cache_entry *ce,
 
 		/*
 		 * Convert from git internal format to working tree format
+		 * unless the smudgeToFile filter can write to the
+		 * file directly.
 		 */
-		if (ce_mode_s_ifmt == S_IFREG &&
+		regular_file = ce_mode_s_ifmt == S_IFREG;
+		smudge_to_file = regular_file
+			&& can_smudge_to_file(ce->name);
+		if (regular_file && !smudge_to_file &&
 		    convert_to_working_tree(ce->name, new, size, &buf)) {
 			free(new);
 			new = strbuf_detach(&buf, &newsize);
@@ -189,13 +195,31 @@ static int write_entry(struct cache_entry *ce,
 			return error_errno("unable to create file %s", path);
 		}
 
-		wrote = write_in_full(fd, new, size);
-		if (!to_tempfile)
-			fstat_done = fstat_output(fd, state, &st);
-		close(fd);
-		free(new);
-		if (wrote != size)
-			return error("unable to write file %s", path);
+		if (!smudge_to_file) {
+			wrote = write_in_full(fd, new, size);
+			if (!to_tempfile)
+				fstat_done = fstat_output(fd, state, &st);
+			close(fd);
+			free(new);
+			if (wrote != size)
+				return error("unable to write file %s", path);
+		}
+		else {
+			close(fd);
+			convert_to_working_tree_filter_to_file(ce->name, path, new, size);
+			free(new);
+			/*
+			 * The smudgeToFile filter may have replaced the
+			 * file; open it to make sure that the file
+			 * exists.
+			 */
+			fd = open(path, O_RDONLY);
+			if (fd < 0)
+				return error_errno("unable to create file %s", path);
+			if (!to_tempfile)
+				fstat_done = fstat_output(fd, state, &st);
+			close(fd);
+		}
 		break;
 	case S_IFGITLINK:
 		if (to_tempfile)
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index bd84b80..ea18b17 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -14,12 +14,20 @@ chmod +x rot13.sh
 
 cat <<EOF >rot13-from-file.sh
 #!$SHELL_PATH
-fsfile="\$1"
+srcfile="\$1"
 touch rot13-from-file.ran
-cat "\$fsfile" | ./rot13.sh
+cat "\$srcfile" | ./rot13.sh
 EOF
 chmod +x rot13-from-file.sh
 
+cat <<EOF >rot13-to-file.sh
+#!$SHELL_PATH
+destfile="\$1"
+touch rot13-to-file.ran
+./rot13.sh >"\$destfile"
+EOF
+chmod +x rot13-to-file.sh
+
 test_expect_success setup '
 	git config filter.rot13.smudge ./rot13.sh &&
 	git config filter.rot13.clean ./rot13.sh &&
@@ -291,6 +299,17 @@ test_expect_success 'cleanFromFile filter is used when adding a file' '
 	test_cmp test fstest.t
 '
 
+test_expect_success 'smudgeToFile filter is used when checking out a file' '
+	test_config filter.rot13.smudgeToFile ./rot13-to-file.sh &&
+
+	rm -f fstest.t &&
+	git checkout -- fstest.t &&
+	test_cmp test fstest.t &&
+
+	test -e rot13-to-file.ran &&
+	rm -f rot13-to-file.ran
+'
+
 test_expect_success 'cleanFromFile filter is not used when clean filter is not configured' '
 	test_config filter.noclean.smudge ./rot13.sh &&
 	test_config filter.noclean.cleanFromFile ./rot13-from-file.sh &&
@@ -304,4 +323,15 @@ test_expect_success 'cleanFromFile filter is not used when clean filter is not c
 	test_cmp test actual
 '
 
+test_expect_success 'smudgeToFile filter is not used when smudge filter is not configured' '
+	test_config filter.nosmudge.clean ./rot13.sh &&
+	test_config filter.nosmudge.smudgeToFile ./rot13-to-file.sh &&
+
+	echo "*.no filter=nosmudge" >.gitattributes &&
+
+	rm -f fstest.t &&
+	git checkout -- fstest.t &&
+	test ! -e rot13-to-file.ran
+'
+
 test_done
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 714E61C67C
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:12 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=Yy9dgbAc;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752555AbcGKWrI (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:08 -0400
Received: from kitenet.net ([66.228.36.95]:60984 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752439AbcGKWrI (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:08 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=ZPsSRNaHriT6igc+PUYizSKSXZl5YDOyDcX0bJMWFqk=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=Yy9dgbAcC69LAmxyt4U9d2lqehM4dKl+NuDIHbQ//uTjX1mmOMkj/Pe4n7vrShEUP
	 D4h/CYU5C4oRTJMhV1MF501fgcvPvOujxUMOviTB+g1EH5YfP989HvZT+7xafE3M4m
	 8+IYWJC1JpDN45UcBwYBROl/ch/87+shPUlms+ds=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 5/8] warn on unusable smudgeToFile/cleanFromFile config
Date:	Mon, 11 Jul 2016 18:45:09 -0400
Message-Id: <1468277112-9909-6-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 2309
Lines: 84

Let the user know when they have a smudgeToFile/cleanFromFile config
that cannot be used because the corresponding smudge/clean config
is missing.

The warning is only displayed a maximum of once per git invocation,
and only when doing an operation that would use the filter.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 convert.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/convert.c b/convert.c
index eb7774f..e1b0b44 100644
--- a/convert.c
+++ b/convert.c
@@ -845,34 +845,50 @@ int would_convert_to_git_filter_fd(const char *path)
 	return apply_filter(path, NULL, NULL, 0, -1, NULL, ca.drv->clean);
 }
 
+static int can_filter_file(const char *filefilter, const char *filefiltername,
+			   const char *stdiofilter, const char *stdiofiltername,
+			   const struct conv_attrs *ca,
+			   int *warncount)
+{
+	if (!filefilter)
+		return 0;
+
+	if (stdiofilter)
+		return 1;
+
+	if (*warncount == 0)
+		warning("Not running your configured filter.%s.%s command, because filter.%s.%s is not configured",
+			ca->drv->name, filefiltername,
+			ca->drv->name, stdiofiltername);
+		*warncount=*warncount+1;
+
+	return 0;
+}
+
 int can_clean_from_file(const char *path)
 {
 	struct conv_attrs ca;
+	static int warncount = 0;
 
 	convert_attrs(&ca, path);
 	if (!ca.drv)
 		return 0;
 
-	/*
-	 * Only use the cleanFromFile filter when the clean filter is also
-	 * configured.
-	 */
-	return (ca.drv->clean_from_file && ca.drv->clean);
+	return can_filter_file(ca.drv->clean_from_file, "cleanFromFile",
+			       ca.drv->clean, "clean", &ca, &warncount);
 }
 
 int can_smudge_to_file(const char *path)
 {
 	struct conv_attrs ca;
+	static int warncount = 0;
 
 	convert_attrs(&ca, path);
 	if (!ca.drv)
 		return 0;
 
-	/*
-	 * Only use the smudgeToFile filter when the smudge filter is also
-	 * configured.
-	 */
-	return (ca.drv->smudge_to_file && ca.drv->smudge);
+	return can_filter_file(ca.drv->smudge_to_file, "smudgeToFile",
+			       ca.drv->smudge, "smudge", &ca, &warncount);
 }
 
 const char *get_convert_attr_ascii(const char *path)
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 839871C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:27 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=e1tj3LJk;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752603AbcGKWrW (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:22 -0400
Received: from kitenet.net ([66.228.36.95]:32788 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752616AbcGKWrT (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:19 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=4aNAzyRt9bz6y9MPC2VC5pj9+5O3Gb5fUsDopvg0K64=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=e1tj3LJkIi1ro6kUH77lZhTIqJt1N6KgyzFzcDDEdrFFz4x49MywJnSCKy9xtgY4h
	 gc/cr1oZKUTrgmSXwMT8HD5yRltK8eWXnXOYn816pWnnRSkFlcwB+VWR4hhVcYahcV
	 KM71p6oYWBbs2BULmxjndGZX1lRSx34zt8DePh2Y=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 6/8] better recovery from failure of smudgeToFile filter
Date:	Mon, 11 Jul 2016 18:45:10 -0400
Message-Id: <1468277112-9909-7-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 4558
Lines: 151

If the smudgeToFile filter fails, it can leave the worktree file with the
wrong content, or even deleted. Recover from this by falling back to
running the smudge filter.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 entry.c               | 66 ++++++++++++++++++++++++++++++++++-----------------
 t/t0021-conversion.sh | 24 +++++++++++++++++++
 2 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/entry.c b/entry.c
index 81d12a1..7811e31 100644
--- a/entry.c
+++ b/entry.c
@@ -182,12 +182,6 @@ static int write_entry(struct cache_entry *ce,
 		regular_file = ce_mode_s_ifmt == S_IFREG;
 		smudge_to_file = regular_file
 			&& can_smudge_to_file(ce->name);
-		if (regular_file && !smudge_to_file &&
-		    convert_to_working_tree(ce->name, new, size, &buf)) {
-			free(new);
-			new = strbuf_detach(&buf, &newsize);
-			size = newsize;
-		}
 
 		fd = open_output_fd(path, ce, to_tempfile);
 		if (fd < 0) {
@@ -195,7 +189,51 @@ static int write_entry(struct cache_entry *ce,
 			return error_errno("unable to create file %s", path);
 		}
 
+		if (smudge_to_file) {
+			close(fd);
+			if (convert_to_working_tree_filter_to_file(ce->name, path, new, size)) {
+				free(new);
+				/*
+				 * The smudgeToFile filter may have replaced
+				 * or deleted the file; reopen it to make
+				 * sure that the file exists.
+				 */
+				fd = open(path, O_RDONLY);
+				if (fd < 0)
+					return error_errno("unable to create file %s", path);
+				if (!to_tempfile)
+					fstat_done = fstat_output(fd, state, &st);
+				close(fd);
+			}
+			else {
+				/*
+				 * The failing smudgeToFile filter may have
+				 * deleted or replaced the file; delete
+				 * the file and re-open for recovery write.
+				 */
+				unlink(path);
+				fd = open_output_fd(path, ce, to_tempfile);
+				if (fd < 0) {
+					free(new);
+					return error_errno("unable to create file %s", path);
+				}
+				/* Fall through to normal write below. */
+				smudge_to_file = 0;
+			}
+		}
+
+		/*
+		 * Not an else of above if (smudge_to_file) because the
+		 * smudgeToFile filter may fail and in that case this is
+		 * run to recover.
+		 */
 		if (!smudge_to_file) {
+			if (regular_file &&
+			    convert_to_working_tree(ce->name, new, size, &buf)) {
+				free(new);
+				new = strbuf_detach(&buf, &newsize);
+				size = newsize;
+			}
 			wrote = write_in_full(fd, new, size);
 			if (!to_tempfile)
 				fstat_done = fstat_output(fd, state, &st);
@@ -204,22 +242,6 @@ static int write_entry(struct cache_entry *ce,
 			if (wrote != size)
 				return error("unable to write file %s", path);
 		}
-		else {
-			close(fd);
-			convert_to_working_tree_filter_to_file(ce->name, path, new, size);
-			free(new);
-			/*
-			 * The smudgeToFile filter may have replaced the
-			 * file; open it to make sure that the file
-			 * exists.
-			 */
-			fd = open(path, O_RDONLY);
-			if (fd < 0)
-				return error_errno("unable to create file %s", path);
-			if (!to_tempfile)
-				fstat_done = fstat_output(fd, state, &st);
-			close(fd);
-		}
 		break;
 	case S_IFGITLINK:
 		if (to_tempfile)
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index ea18b17..0efad9b 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -28,6 +28,14 @@ touch rot13-to-file.ran
 EOF
 chmod +x rot13-to-file.sh
 
+cat <<EOF >delete-file-and-fail.sh
+#!$SHELL_PATH
+destfile="\$1"
+rm -f "\$destfile"
+exit 1
+EOF
+chmod +x delete-file-and-fail.sh
+
 test_expect_success setup '
 	git config filter.rot13.smudge ./rot13.sh &&
 	git config filter.rot13.clean ./rot13.sh &&
@@ -310,6 +318,22 @@ test_expect_success 'smudgeToFile filter is used when checking out a file' '
 	rm -f rot13-to-file.ran
 '
 
+test_expect_success 'recovery from failure of smudgeToFile filter, using smudge filter' '
+	test_config filter.rot13.smudgeToFile false &&
+
+	rm -f fstest.t &&
+	git checkout -- fstest.t &&
+	test_cmp test fstest.t
+'
+
+test_expect_success 'recovery from failure of smudgeToFile filter that deletes the worktree file' '
+	test_config filter.rot13.smudgeToFile ./delete-file-and-fail.sh &&
+
+	rm -f fstest.t &&
+	git checkout -- fstest.t &&
+	test_cmp test fstest.t
+'
+
 test_expect_success 'cleanFromFile filter is not used when clean filter is not configured' '
 	test_config filter.noclean.smudge ./rot13.sh &&
 	test_config filter.noclean.cleanFromFile ./rot13-from-file.sh &&
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id 3B2531C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:23 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=P7RXYLHP;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752629AbcGKWrT (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:19 -0400
Received: from kitenet.net ([66.228.36.95]:32782 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752603AbcGKWrS (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:18 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=R6DA3FWAltlIvvD5mJEp7ZgM7JFZFfGDS/9auV9Z+0Q=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=P7RXYLHPbs0CXSl4ChFu0IJTC7WGua7f0VyocRm/r3ZZK/2HscKr3lMHDy0fxfD3I
	 grgLgEiaffIZ5+vMX0FWQIYDLISJD4NlDMYYt3NoONm10nDHJp/vSm1/YdyoaT8+3p
	 RnZbAzgY6m43Lhx7BxNApQ8/UPzUL5hWD45Jl5YU=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 7/8] use smudgeToFile filter in git am
Date:	Mon, 11 Jul 2016 18:45:11 -0400
Message-Id: <1468277112-9909-8-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 4808
Lines: 156

git am updates the work tree and so should use the smudgeToFile filter.

This includes some refactoring into convert_to_working_tree_filter_to_file
to make it check the file after running the smudgeToFile command, and clean
up from a failing command.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 apply.c               | 16 ++++++++++++++++
 convert.c             | 25 +++++++++++++++++++++++--
 entry.c               | 21 ++++-----------------
 t/t0021-conversion.sh | 13 +++++++++++++
 4 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/apply.c b/apply.c
index 4a6b2db..7db8344 100644
--- a/apply.c
+++ b/apply.c
@@ -4322,6 +4322,22 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
 	if (fd < 0)
 		return 1;
 
+	if (can_smudge_to_file(path)) {
+		close(fd);
+		fd = convert_to_working_tree_filter_to_file(path, path, buf, size);
+		if (fd < 0) {
+			/* smudgeToFile filter failed; continue
+			 * with regular file creation instead. */
+			fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
+			if (fd < 0)
+				return -1;
+		}
+		else {
+			close(fd);
+			return 0;
+		}
+	}
+
 	if (convert_to_working_tree(path, buf, size, &nbuf)) {
 		size = nbuf.len;
 		buf  = nbuf.buf;
diff --git a/convert.c b/convert.c
index e1b0b44..3746ad5 100644
--- a/convert.c
+++ b/convert.c
@@ -1030,13 +1030,34 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
 	return convert_to_working_tree_internal(path, NULL, src, len, dst, 0);
 }
 
+/*
+ * Returns fd open to read the worktree file on success.
+ * On failure, the worktree file will not exist.
+ */
 int convert_to_working_tree_filter_to_file(const char *path, const char *destpath, const char *src, size_t len)
 {
 	struct strbuf output = STRBUF_INIT;
-	int ret = convert_to_working_tree_internal(path, destpath, src, len, &output, 0);
+	int ok = convert_to_working_tree_internal(path, destpath, src, len, &output, 0);
 	/* The smudgeToFile filter stdout is not used. */
 	strbuf_release(&output);
-	return ret;
+	if (ok) {
+		/*
+		 * Open the file to make sure that it's present
+		 * (and readable) after the command populated it.
+		 */
+		int fd = open(path, O_RDONLY);
+		if (fd < 0)
+			unlink(path);
+		return fd;
+	}
+	else {
+		/*
+		 * The command could have created the file before failing,
+		 * so delete it.
+		 */
+		unlink(path);
+		return -1;
+	}
 }
 
 int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
diff --git a/entry.c b/entry.c
index 7811e31..40662eb 100644
--- a/entry.c
+++ b/entry.c
@@ -191,34 +191,21 @@ static int write_entry(struct cache_entry *ce,
 
 		if (smudge_to_file) {
 			close(fd);
-			if (convert_to_working_tree_filter_to_file(ce->name, path, new, size)) {
+			fd = convert_to_working_tree_filter_to_file(ce->name, path, new, size);
+			if (fd >= 0) {
 				free(new);
-				/*
-				 * The smudgeToFile filter may have replaced
-				 * or deleted the file; reopen it to make
-				 * sure that the file exists.
-				 */
-				fd = open(path, O_RDONLY);
-				if (fd < 0)
-					return error_errno("unable to create file %s", path);
 				if (!to_tempfile)
 					fstat_done = fstat_output(fd, state, &st);
 				close(fd);
 			}
 			else {
-				/*
-				 * The failing smudgeToFile filter may have
-				 * deleted or replaced the file; delete
-				 * the file and re-open for recovery write.
-				 */
-				unlink(path);
+				/* Fall through to normal write below. */
+				smudge_to_file = 0;
 				fd = open_output_fd(path, ce, to_tempfile);
 				if (fd < 0) {
 					free(new);
 					return error_errno("unable to create file %s", path);
 				}
-				/* Fall through to normal write below. */
-				smudge_to_file = 0;
 			}
 		}
 
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 0efad9b..42b28aa 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -334,6 +334,19 @@ test_expect_success 'recovery from failure of smudgeToFile filter that deletes t
 	test_cmp test fstest.t
 '
 
+test_expect_success 'smudgeToFile filter is used by git am' '
+	test_config filter.rot13.smudgeToFile ./rot13-to-file.sh &&
+
+	git commit fstest.t -m "added fstest.t" &&
+	git format-patch HEAD^ --stdout >fstest.patch &&
+	git reset --hard HEAD^ &&
+	git am fstest.patch &&
+
+	test -e rot13-to-file.ran &&
+	rm -f rot13-to-file.ran &&
+	test_cmp test fstest.t
+'
+
 test_expect_success 'cleanFromFile filter is not used when clean filter is not configured' '
 	test_config filter.noclean.smudge ./rot13.sh &&
 	test_config filter.noclean.cleanFromFile ./rot13-from-file.sh &&
-- 
2.8.1

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

From mairix@mairix Mon Jan  1 12:34:56 1970
X-source-folder: /home/joey/mail/.git/annex/objects/0k/FJ/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz/SHA256E-s162778--6d2a0fc6afd1077eccdca2e92f314c00ef70a06273242429035e0ce52cce2e13.gz
Return-Path: <git-owner@vger.kernel.org>
X-Original-To: joey@kitenet.net
Delivered-To: joey@kitenet.net
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
	by kitenet.net (Postfix) with ESMTP id C58671C677
	for <joey@kitenet.net>; Mon, 11 Jul 2016 18:47:18 -0400 (EDT)
Authentication-Results: kitenet.net;
	dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=joeyh.name header.i=@joeyh.name header.b=VKChWnWm;
	dkim-atps=neutral
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
	id S1752615AbcGKWrR (ORCPT <rfc822;joey@kitenet.net>);
	Mon, 11 Jul 2016 18:47:17 -0400
Received: from kitenet.net ([66.228.36.95]:32778 "EHLO kitenet.net"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752603AbcGKWrO (ORCPT <rfc822;git@vger.kernel.org>);
	Mon, 11 Jul 2016 18:47:14 -0400
X-Question: 42
DKIM-Signature:	v=1; a=rsa-sha256; c=simple/simple; d=joeyh.name; s=mail;
	t=1468277198; bh=e7pd1+fJ7kJE3zbr6Uuf5rQkwlF5ZqMSMu31as4SNuw=;
	h=From:To:Cc:Subject:Date:In-Reply-To:References:From;
	b=VKChWnWmsu86vvKjaYknMgW76bozccToHJNzUBKXMXKt57vEc+PiDgxiMNKvA57iJ
	 /S26T8zVRqNUsPdzXsLMoCVA+T2EPLwSv/dLjBIwrTT+yveUiaH2Q4U9jzqDkU/GYy
	 8iEtbg7ly/pnrWgjApNsnbMY5OogcAINTDod/flY=
From:	Joey Hess <joeyh@joeyh.name>
To:	git@vger.kernel.org
Cc:	Joey Hess <joeyh@joeyh.name>
Subject: [PATCH v5 8/8] use smudgeToFile filter in recursive merge
Date:	Mon, 11 Jul 2016 18:45:12 -0400
Message-Id: <1468277112-9909-9-git-send-email-joeyh@joeyh.name>
X-Mailer: git-send-email 2.8.1
In-Reply-To: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
References: <1468277112-9909-1-git-send-email-joeyh@joeyh.name>
X-Spam-Status: No, score=-8.2 required=10.0 tests=BAYES_00,DKIM_SIGNED,
	HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,
	URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on kite.kitenet.net
Sender:	git-owner@vger.kernel.org
Precedence: bulk
List-ID: <git.vger.kernel.org>
X-Mailing-List:	git@vger.kernel.org
Content-Length: 3928
Lines: 134

Recursive merge updates the work tree and so should use the smudgeToFile
filter.

At this point, smudgeToFile is run by everything that updates work
tree files.

Signed-off-by: Joey Hess <joeyh@joeyh.name>
---
 merge-recursive.c     | 53 ++++++++++++++++++++++++++++++++++++++++-----------
 t/t0021-conversion.sh | 16 +++++++++++++++-
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index a4a1195..5fe3f50 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -758,6 +758,7 @@ static void update_file_flags(struct merge_options *o,
 		enum object_type type;
 		void *buf;
 		unsigned long size;
+		int isreg;
 
 		if (S_ISGITLINK(mode)) {
 			/*
@@ -774,22 +775,16 @@ static void update_file_flags(struct merge_options *o,
 			die(_("cannot read object %s '%s'"), oid_to_hex(oid), path);
 		if (type != OBJ_BLOB)
 			die(_("blob expected for %s '%s'"), oid_to_hex(oid), path);
-		if (S_ISREG(mode)) {
-			struct strbuf strbuf = STRBUF_INIT;
-			if (convert_to_working_tree(path, buf, size, &strbuf)) {
-				free(buf);
-				size = strbuf.len;
-				buf = strbuf_detach(&strbuf, NULL);
-			}
-		}
 
 		if (make_room_for_path(o, path) < 0) {
 			update_wd = 0;
 			free(buf);
 			goto update_index;
 		}
-		if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
+		isreg = S_ISREG(mode);
+		if (isreg || (!has_symlinks && S_ISLNK(mode))) {
 			int fd;
+			int smudge_to_file;
 			if (mode & 0100)
 				mode = 0777;
 			else
@@ -797,8 +792,44 @@ static void update_file_flags(struct merge_options *o,
 			fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
 			if (fd < 0)
 				die_errno(_("failed to open '%s'"), path);
-			write_in_full(fd, buf, size);
-			close(fd);
+
+			smudge_to_file = can_smudge_to_file(path);
+			if (smudge_to_file) {
+				close(fd);
+				fd = convert_to_working_tree_filter_to_file(path, path, buf, size);
+				if (fd < 0) {
+					/*
+					 * smudgeToFile filter failed;
+					 * continue with regular file
+					 * creation.
+					 */
+					smudge_to_file = 0;
+					fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
+					if (fd < 0)
+						die_errno(_("failed to open '%s'"), path);
+				}
+				else {
+					close(fd);
+				}
+			}
+
+			/*
+			 * Not an else of above if (smudge_to_file) because
+			 * the smudgeToFile filter may fail and in that case
+			 * this is run to recover.
+			 */
+			if (!smudge_to_file) {
+				if (isreg) {
+					struct strbuf strbuf = STRBUF_INIT;
+					if (convert_to_working_tree(path, buf, size, &strbuf)) {
+						free(buf);
+						size = strbuf.len;
+						buf = strbuf_detach(&strbuf, NULL);
+					}
+				}
+				write_in_full(fd, buf, size);
+				close(fd);
+			}
 		} else if (S_ISLNK(mode)) {
 			char *lnk = xmemdupz(buf, size);
 			safe_create_leading_directories_const(path);
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 42b28aa..64b2b8f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -334,10 +334,24 @@ test_expect_success 'recovery from failure of smudgeToFile filter that deletes t
 	test_cmp test fstest.t
 '
 
+test_expect_success 'smudgeToFile filter is used in merge' '
+	test_config filter.rot13.smudgeToFile ./rot13-to-file.sh &&
+
+	git commit -m "added fstest.t" fstest.t &&
+	git checkout -b old &&
+	git reset --hard HEAD^ &&
+	git merge master &&
+	git checkout master &&
+
+	test -e rot13-to-file.ran &&
+	rm -f rot13-to-file.ran &&
+
+	test_cmp test fstest.t
+'
+
 test_expect_success 'smudgeToFile filter is used by git am' '
 	test_config filter.rot13.smudgeToFile ./rot13-to-file.sh &&
 
-	git commit fstest.t -m "added fstest.t" &&
 	git format-patch HEAD^ --stdout >fstest.patch &&
 	git reset --hard HEAD^ &&
 	git am fstest.patch &&
-- 
2.8.1

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

