2023-05-16 14:33:57 +08:00
|
|
|
#include "git-compat-util.h"
|
2023-04-11 11:00:39 +08:00
|
|
|
#include "advice.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2023-04-11 11:00:40 +08:00
|
|
|
#include "convert.h"
|
2023-04-23 04:17:12 +08:00
|
|
|
#include "copy.h"
|
2023-03-21 14:25:54 +08:00
|
|
|
#include "gettext.h"
|
2023-02-24 08:09:27 +08:00
|
|
|
#include "hex.h"
|
2018-05-16 07:42:15 +08:00
|
|
|
#include "object-store.h"
|
2007-04-13 13:30:05 +08:00
|
|
|
#include "attr.h"
|
2007-04-22 10:09:02 +08:00
|
|
|
#include "run-command.h"
|
2010-12-22 22:40:13 +08:00
|
|
|
#include "quote.h"
|
2023-05-16 14:33:56 +08:00
|
|
|
#include "read-cache-ll.h"
|
2012-02-21 04:53:37 +08:00
|
|
|
#include "sigchain.h"
|
2016-10-17 07:20:37 +08:00
|
|
|
#include "pkt-line.h"
|
2017-05-05 23:28:01 +08:00
|
|
|
#include "sub-process.h"
|
2023-04-11 11:00:38 +08:00
|
|
|
#include "trace.h"
|
2018-04-16 02:16:07 +08:00
|
|
|
#include "utf8.h"
|
2019-09-03 06:39:44 +08:00
|
|
|
#include "ll-merge.h"
|
2023-03-21 14:26:01 +08:00
|
|
|
#include "wrapper.h"
|
2007-04-13 13:30:05 +08:00
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
/*
|
|
|
|
* convert.c - convert a file when checking it out and checking it in.
|
|
|
|
*
|
|
|
|
* This should use the pathname to decide on whether it wants to do some
|
|
|
|
* more interesting conversions (automatic gzip/unzip, general format
|
|
|
|
* conversions etc etc), but by default it just does automatic CRLF<->LF
|
2010-06-05 03:29:08 +08:00
|
|
|
* translation when the "text" attribute or "auto_crlf" option is set.
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
*/
|
|
|
|
|
2016-01-16 14:50:02 +08:00
|
|
|
/* Stat bits: When BIN is set, the txt bits are unset */
|
|
|
|
#define CONVERT_STAT_BITS_TXT_LF 0x1
|
|
|
|
#define CONVERT_STAT_BITS_TXT_CRLF 0x2
|
|
|
|
#define CONVERT_STAT_BITS_BIN 0x4
|
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
struct text_stat {
|
2008-01-16 09:59:12 +08:00
|
|
|
/* NUL, CR, LF and CRLF counts */
|
2016-02-11 00:24:43 +08:00
|
|
|
unsigned nul, lonecr, lonelf, crlf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
|
|
|
/* These are just approximations! */
|
|
|
|
unsigned printable, nonprintable;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
memset(stats, 0, sizeof(*stats));
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
unsigned char c = buf[i];
|
|
|
|
if (c == '\r') {
|
2016-02-11 00:24:43 +08:00
|
|
|
if (i+1 < size && buf[i+1] == '\n') {
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
stats->crlf++;
|
2016-02-11 00:24:43 +08:00
|
|
|
i++;
|
|
|
|
} else
|
|
|
|
stats->lonecr++;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '\n') {
|
2016-02-11 00:24:43 +08:00
|
|
|
stats->lonelf++;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == 127)
|
|
|
|
/* DEL */
|
|
|
|
stats->nonprintable++;
|
|
|
|
else if (c < 32) {
|
|
|
|
switch (c) {
|
|
|
|
/* BS, HT, ESC and FF */
|
|
|
|
case '\b': case '\t': case '\033': case '\014':
|
|
|
|
stats->printable++;
|
|
|
|
break;
|
2008-01-16 09:59:12 +08:00
|
|
|
case 0:
|
|
|
|
stats->nul++;
|
|
|
|
/* fall through */
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
default:
|
|
|
|
stats->nonprintable++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
stats->printable++;
|
|
|
|
}
|
2008-07-12 00:48:16 +08:00
|
|
|
|
|
|
|
/* If file ends with EOF then don't count this EOF as non-printable. */
|
|
|
|
if (size >= 1 && buf[size-1] == '\032')
|
|
|
|
stats->nonprintable--;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The same heuristics as diff.c::mmfile_is_binary()
|
2016-01-16 14:50:02 +08:00
|
|
|
* We treat files with bare CR as binary
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
*/
|
2019-01-24 21:12:41 +08:00
|
|
|
static int convert_is_binary(const struct text_stat *stats)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
2016-02-11 00:24:43 +08:00
|
|
|
if (stats->lonecr)
|
2016-01-16 14:50:02 +08:00
|
|
|
return 1;
|
2008-01-16 09:59:12 +08:00
|
|
|
if (stats->nul)
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
if ((stats->printable >> 7) < stats->nonprintable)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-16 14:50:02 +08:00
|
|
|
static unsigned int gather_convert_stats(const char *data, unsigned long size)
|
|
|
|
{
|
|
|
|
struct text_stat stats;
|
2016-02-11 00:24:43 +08:00
|
|
|
int ret = 0;
|
2016-01-16 14:50:02 +08:00
|
|
|
if (!data || !size)
|
|
|
|
return 0;
|
|
|
|
gather_stats(data, size, &stats);
|
2019-01-24 21:12:41 +08:00
|
|
|
if (convert_is_binary(&stats))
|
2016-02-11 00:24:43 +08:00
|
|
|
ret |= CONVERT_STAT_BITS_BIN;
|
|
|
|
if (stats.crlf)
|
|
|
|
ret |= CONVERT_STAT_BITS_TXT_CRLF;
|
|
|
|
if (stats.lonelf)
|
|
|
|
ret |= CONVERT_STAT_BITS_TXT_LF;
|
|
|
|
|
|
|
|
return ret;
|
2016-01-16 14:50:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *gather_convert_stats_ascii(const char *data, unsigned long size)
|
|
|
|
{
|
|
|
|
unsigned int convert_stats = gather_convert_stats(data, size);
|
|
|
|
|
|
|
|
if (convert_stats & CONVERT_STAT_BITS_BIN)
|
|
|
|
return "-text";
|
|
|
|
switch (convert_stats) {
|
|
|
|
case CONVERT_STAT_BITS_TXT_LF:
|
|
|
|
return "lf";
|
|
|
|
case CONVERT_STAT_BITS_TXT_CRLF:
|
|
|
|
return "crlf";
|
|
|
|
case CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF:
|
|
|
|
return "mixed";
|
|
|
|
default:
|
|
|
|
return "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
const char *get_cached_convert_stats_ascii(struct index_state *istate,
|
2017-06-13 06:13:52 +08:00
|
|
|
const char *path)
|
2016-01-16 14:50:02 +08:00
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
unsigned long sz;
|
2017-06-13 06:13:52 +08:00
|
|
|
void *data = read_blob_data_from_index(istate, path, &sz);
|
2016-01-16 14:50:02 +08:00
|
|
|
ret = gather_convert_stats_ascii(data, sz);
|
|
|
|
free(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_wt_convert_stats_ascii(const char *path)
|
|
|
|
{
|
|
|
|
const char *ret = "";
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
if (strbuf_read_file(&sb, path, 0) >= 0)
|
|
|
|
ret = gather_convert_stats_ascii(sb.buf, sb.len);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-06 00:13:25 +08:00
|
|
|
static int text_eol_is_crlf(void)
|
|
|
|
{
|
|
|
|
if (auto_crlf == AUTO_CRLF_TRUE)
|
|
|
|
return 1;
|
|
|
|
else if (auto_crlf == AUTO_CRLF_INPUT)
|
|
|
|
return 0;
|
|
|
|
if (core_eol == EOL_CRLF)
|
|
|
|
return 1;
|
|
|
|
if (core_eol == EOL_UNSET && EOL_NATIVE == EOL_CRLF)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-16 22:50:30 +08:00
|
|
|
static enum eol output_eol(enum convert_crlf_action crlf_action)
|
2010-07-03 03:20:47 +08:00
|
|
|
{
|
2011-05-10 04:12:57 +08:00
|
|
|
switch (crlf_action) {
|
2010-06-05 03:29:08 +08:00
|
|
|
case CRLF_BINARY:
|
|
|
|
return EOL_UNSET;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_CRLF:
|
2010-06-05 03:29:08 +08:00
|
|
|
return EOL_CRLF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_INPUT:
|
2010-06-05 03:29:08 +08:00
|
|
|
return EOL_LF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_UNDEFINED:
|
|
|
|
case CRLF_AUTO_CRLF:
|
2016-06-28 16:01:13 +08:00
|
|
|
return EOL_CRLF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_INPUT:
|
2016-06-28 16:01:13 +08:00
|
|
|
return EOL_LF;
|
2010-06-05 03:29:08 +08:00
|
|
|
case CRLF_TEXT:
|
|
|
|
case CRLF_AUTO:
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
/* fall through */
|
2016-02-06 00:13:25 +08:00
|
|
|
return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
|
2010-06-05 03:29:08 +08:00
|
|
|
}
|
2018-07-21 15:49:29 +08:00
|
|
|
warning(_("illegal crlf_action %d"), (int)crlf_action);
|
2011-05-10 03:52:12 +08:00
|
|
|
return core_eol;
|
2010-06-05 03:29:08 +08:00
|
|
|
}
|
|
|
|
|
2020-09-30 20:27:53 +08:00
|
|
|
static void check_global_conv_flags_eol(const char *path,
|
2016-08-14 05:29:27 +08:00
|
|
|
struct text_stat *old_stats, struct text_stat *new_stats,
|
2018-01-14 06:49:31 +08:00
|
|
|
int conv_flags)
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
{
|
2016-08-14 05:29:27 +08:00
|
|
|
if (old_stats->crlf && !new_stats->crlf ) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
/*
|
2016-08-14 05:29:27 +08:00
|
|
|
* CRLFs would not be restored by checkout
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
*/
|
2018-01-14 06:49:31 +08:00
|
|
|
if (conv_flags & CONV_EOL_RNDTRP_DIE)
|
2018-07-21 15:49:19 +08:00
|
|
|
die(_("CRLF would be replaced by LF in %s"), path);
|
2018-01-14 06:49:31 +08:00
|
|
|
else if (conv_flags & CONV_EOL_RNDTRP_WARN)
|
2022-04-08 12:41:54 +08:00
|
|
|
warning(_("in the working copy of '%s', CRLF will be"
|
|
|
|
" replaced by LF the next time Git touches"
|
|
|
|
" it"), path);
|
2016-08-14 05:29:27 +08:00
|
|
|
} else if (old_stats->lonelf && !new_stats->lonelf ) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
/*
|
2016-08-14 05:29:27 +08:00
|
|
|
* CRLFs would be added by checkout
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
*/
|
2018-01-14 06:49:31 +08:00
|
|
|
if (conv_flags & CONV_EOL_RNDTRP_DIE)
|
|
|
|
die(_("LF would be replaced by CRLF in %s"), path);
|
|
|
|
else if (conv_flags & CONV_EOL_RNDTRP_WARN)
|
2022-04-08 12:41:54 +08:00
|
|
|
warning(_("in the working copy of '%s', LF will be"
|
|
|
|
" replaced by CRLF the next time Git touches"
|
|
|
|
" it"), path);
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
static int has_crlf_in_index(struct index_state *istate, const char *path)
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
{
|
|
|
|
unsigned long sz;
|
|
|
|
void *data;
|
2017-11-26 20:20:52 +08:00
|
|
|
const char *crp;
|
|
|
|
int has_crlf = 0;
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
|
2017-06-13 06:13:53 +08:00
|
|
|
data = read_blob_data_from_index(istate, path, &sz);
|
2013-04-13 21:28:32 +08:00
|
|
|
if (!data)
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
return 0;
|
2017-11-26 20:20:52 +08:00
|
|
|
|
|
|
|
crp = memchr(data, '\r', sz);
|
|
|
|
if (crp) {
|
|
|
|
unsigned int ret_stats;
|
|
|
|
ret_stats = gather_convert_stats(data, sz);
|
|
|
|
if (!(ret_stats & CONVERT_STAT_BITS_BIN) &&
|
|
|
|
(ret_stats & CONVERT_STAT_BITS_TXT_CRLF))
|
|
|
|
has_crlf = 1;
|
|
|
|
}
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
free(data);
|
2017-11-26 20:20:52 +08:00
|
|
|
return has_crlf;
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:12:41 +08:00
|
|
|
static int will_convert_lf_to_crlf(struct text_stat *stats,
|
2020-12-16 22:50:30 +08:00
|
|
|
enum convert_crlf_action crlf_action)
|
2016-08-14 05:29:27 +08:00
|
|
|
{
|
|
|
|
if (output_eol(crlf_action) != EOL_CRLF)
|
|
|
|
return 0;
|
|
|
|
/* No "naked" LF? Nothing to convert, regardless. */
|
|
|
|
if (!stats->lonelf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
|
|
|
/* If we have any CR or CRLF line endings, we do not touch it */
|
|
|
|
/* This is the new safer autocrlf-handling */
|
|
|
|
if (stats->lonecr || stats->crlf)
|
|
|
|
return 0;
|
|
|
|
|
2019-01-24 21:12:41 +08:00
|
|
|
if (convert_is_binary(stats))
|
2016-08-14 05:29:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:08 +08:00
|
|
|
static int validate_encoding(const char *path, const char *enc,
|
|
|
|
const char *data, size_t len, int die_on_error)
|
|
|
|
{
|
2019-11-09 04:27:34 +08:00
|
|
|
const char *stripped;
|
|
|
|
|
2018-04-16 02:16:08 +08:00
|
|
|
/* We only check for UTF here as UTF?? can be an alias for UTF-?? */
|
2019-11-09 04:27:34 +08:00
|
|
|
if (skip_iprefix(enc, "UTF", &stripped)) {
|
|
|
|
skip_prefix(stripped, "-", &stripped);
|
|
|
|
|
2018-04-16 02:16:08 +08:00
|
|
|
/*
|
|
|
|
* Check for detectable errors in UTF encodings
|
|
|
|
*/
|
|
|
|
if (has_prohibited_utf_bom(enc, data, len)) {
|
|
|
|
const char *error_msg = _(
|
|
|
|
"BOM is prohibited in '%s' if encoded as %s");
|
|
|
|
/*
|
|
|
|
* This advice is shown for UTF-??BE and UTF-??LE encodings.
|
|
|
|
* We cut off the last two characters of the encoding name
|
|
|
|
* to generate the encoding name suitable for BOMs.
|
|
|
|
*/
|
|
|
|
const char *advise_msg = _(
|
|
|
|
"The file '%s' contains a byte order "
|
2019-11-09 04:27:34 +08:00
|
|
|
"mark (BOM). Please use UTF-%.*s as "
|
2018-04-16 02:16:08 +08:00
|
|
|
"working-tree-encoding.");
|
2019-11-09 04:27:34 +08:00
|
|
|
int stripped_len = strlen(stripped) - strlen("BE");
|
|
|
|
advise(advise_msg, path, stripped_len, stripped);
|
2018-04-16 02:16:08 +08:00
|
|
|
if (die_on_error)
|
|
|
|
die(error_msg, path, enc);
|
|
|
|
else {
|
|
|
|
return error(error_msg, path, enc);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (is_missing_required_utf_bom(enc, data, len)) {
|
|
|
|
const char *error_msg = _(
|
|
|
|
"BOM is required in '%s' if encoded as %s");
|
|
|
|
const char *advise_msg = _(
|
|
|
|
"The file '%s' is missing a byte order "
|
|
|
|
"mark (BOM). Please use UTF-%sBE or UTF-%sLE "
|
|
|
|
"(depending on the byte order) as "
|
|
|
|
"working-tree-encoding.");
|
|
|
|
advise(advise_msg, path, stripped, stripped);
|
|
|
|
if (die_on_error)
|
|
|
|
die(error_msg, path, enc);
|
|
|
|
else {
|
|
|
|
return error(error_msg, path, enc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:09 +08:00
|
|
|
static void trace_encoding(const char *context, const char *path,
|
|
|
|
const char *encoding, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
static struct trace_key coe = TRACE_KEY_INIT(WORKING_TREE_ENCODING);
|
|
|
|
struct strbuf trace = STRBUF_INIT;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding);
|
|
|
|
for (i = 0; i < len && buf; ++i) {
|
|
|
|
strbuf_addf(
|
2018-07-10 03:25:34 +08:00
|
|
|
&trace, "| \033[2m%2i:\033[0m %2x \033[2m%c\033[0m%c",
|
2018-04-16 02:16:09 +08:00
|
|
|
i,
|
|
|
|
(unsigned char) buf[i],
|
|
|
|
(buf[i] > 32 && buf[i] < 127 ? buf[i] : ' '),
|
|
|
|
((i+1) % 8 && (i+1) < len ? ' ' : '\n')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
strbuf_addchars(&trace, '\n', 1);
|
|
|
|
|
|
|
|
trace_strbuf(&coe, &trace);
|
|
|
|
strbuf_release(&trace);
|
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:10 +08:00
|
|
|
static int check_roundtrip(const char *enc_name)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* check_roundtrip_encoding contains a string of comma and/or
|
|
|
|
* space separated encodings (eg. "UTF-16, ASCII, CP1125").
|
|
|
|
* Search for the given encoding in that string.
|
|
|
|
*/
|
|
|
|
const char *found = strcasestr(check_roundtrip_encoding, enc_name);
|
|
|
|
const char *next;
|
|
|
|
int len;
|
|
|
|
if (!found)
|
|
|
|
return 0;
|
|
|
|
next = found + strlen(enc_name);
|
|
|
|
len = strlen(check_roundtrip_encoding);
|
|
|
|
return (found && (
|
|
|
|
/*
|
|
|
|
* check that the found encoding is at the
|
|
|
|
* beginning of check_roundtrip_encoding or
|
|
|
|
* that it is prefixed with a space or comma
|
|
|
|
*/
|
|
|
|
found == check_roundtrip_encoding || (
|
|
|
|
(isspace(found[-1]) || found[-1] == ',')
|
|
|
|
)
|
|
|
|
) && (
|
|
|
|
/*
|
|
|
|
* check that the found encoding is at the
|
|
|
|
* end of check_roundtrip_encoding or
|
|
|
|
* that it is suffixed with a space or comma
|
|
|
|
*/
|
|
|
|
next == check_roundtrip_encoding + len || (
|
|
|
|
next < check_roundtrip_encoding + len &&
|
|
|
|
(isspace(next[0]) || next[0] == ',')
|
|
|
|
)
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:07 +08:00
|
|
|
static const char *default_encoding = "UTF-8";
|
|
|
|
|
|
|
|
static int encode_to_git(const char *path, const char *src, size_t src_len,
|
|
|
|
struct strbuf *buf, const char *enc, int conv_flags)
|
|
|
|
{
|
|
|
|
char *dst;
|
2018-07-24 18:50:33 +08:00
|
|
|
size_t dst_len;
|
2018-04-16 02:16:07 +08:00
|
|
|
int die_on_error = conv_flags & CONV_WRITE_OBJECT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No encoding is specified or there is nothing to encode.
|
|
|
|
* Tell the caller that the content was not modified.
|
|
|
|
*/
|
|
|
|
if (!enc || (src && !src_len))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Looks like we got called from "would_convert_to_git()".
|
|
|
|
* This means Git wants to know if it would encode (= modify!)
|
|
|
|
* the content. Let's answer with "yes", since an encoding was
|
|
|
|
* specified.
|
|
|
|
*/
|
|
|
|
if (!buf && !src)
|
|
|
|
return 1;
|
|
|
|
|
2018-04-16 02:16:08 +08:00
|
|
|
if (validate_encoding(path, enc, src, src_len, die_on_error))
|
|
|
|
return 0;
|
|
|
|
|
2018-04-16 02:16:09 +08:00
|
|
|
trace_encoding("source", path, enc, src, src_len);
|
2018-04-16 02:16:07 +08:00
|
|
|
dst = reencode_string_len(src, src_len, default_encoding, enc,
|
|
|
|
&dst_len);
|
|
|
|
if (!dst) {
|
|
|
|
/*
|
|
|
|
* We could add the blob "as-is" to Git. However, on checkout
|
2019-11-06 01:07:23 +08:00
|
|
|
* we would try to re-encode to the original encoding. This
|
2018-04-16 02:16:07 +08:00
|
|
|
* would fail and we would leave the user with a messed-up
|
|
|
|
* working tree. Let's try to avoid this by screaming loud.
|
|
|
|
*/
|
|
|
|
const char* msg = _("failed to encode '%s' from %s to %s");
|
|
|
|
if (die_on_error)
|
|
|
|
die(msg, path, enc, default_encoding);
|
|
|
|
else {
|
|
|
|
error(msg, path, enc, default_encoding);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2018-04-16 02:16:09 +08:00
|
|
|
trace_encoding("destination", path, default_encoding, dst, dst_len);
|
2018-04-16 02:16:07 +08:00
|
|
|
|
2018-04-16 02:16:10 +08:00
|
|
|
/*
|
|
|
|
* UTF supports lossless conversion round tripping [1] and conversions
|
|
|
|
* between UTF and other encodings are mostly round trip safe as
|
|
|
|
* Unicode aims to be a superset of all other character encodings.
|
|
|
|
* However, certain encodings (e.g. SHIFT-JIS) are known to have round
|
|
|
|
* trip issues [2]. Check the round trip conversion for all encodings
|
|
|
|
* listed in core.checkRoundtripEncoding.
|
|
|
|
*
|
|
|
|
* The round trip check is only performed if content is written to Git.
|
|
|
|
* This ensures that no information is lost during conversion to/from
|
|
|
|
* the internal UTF-8 representation.
|
|
|
|
*
|
|
|
|
* Please note, the code below is not tested because I was not able to
|
|
|
|
* generate a faulty round trip without an iconv error. Iconv errors
|
|
|
|
* are already caught above.
|
|
|
|
*
|
|
|
|
* [1] http://unicode.org/faq/utf_bom.html#gen2
|
|
|
|
* [2] https://support.microsoft.com/en-us/help/170559/prb-conversion-problem-between-shift-jis-and-unicode
|
|
|
|
*/
|
|
|
|
if (die_on_error && check_roundtrip(enc)) {
|
|
|
|
char *re_src;
|
2018-07-24 18:50:33 +08:00
|
|
|
size_t re_src_len;
|
2018-04-16 02:16:10 +08:00
|
|
|
|
|
|
|
re_src = reencode_string_len(dst, dst_len,
|
|
|
|
enc, default_encoding,
|
|
|
|
&re_src_len);
|
|
|
|
|
|
|
|
trace_printf("Checking roundtrip encoding for %s...\n", enc);
|
|
|
|
trace_encoding("reencoded source", path, enc,
|
|
|
|
re_src, re_src_len);
|
|
|
|
|
|
|
|
if (!re_src || src_len != re_src_len ||
|
|
|
|
memcmp(src, re_src, src_len)) {
|
|
|
|
const char* msg = _("encoding '%s' from %s to %s and "
|
|
|
|
"back is not the same");
|
|
|
|
die(msg, path, enc, default_encoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(re_src);
|
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:07 +08:00
|
|
|
strbuf_attach(buf, dst, dst_len, dst_len + 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int encode_to_worktree(const char *path, const char *src, size_t src_len,
|
|
|
|
struct strbuf *buf, const char *enc)
|
|
|
|
{
|
|
|
|
char *dst;
|
2018-07-24 18:50:33 +08:00
|
|
|
size_t dst_len;
|
2018-04-16 02:16:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No encoding is specified or there is nothing to encode.
|
|
|
|
* Tell the caller that the content was not modified.
|
|
|
|
*/
|
|
|
|
if (!enc || (src && !src_len))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
dst = reencode_string_len(src, src_len, enc, default_encoding,
|
|
|
|
&dst_len);
|
|
|
|
if (!dst) {
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("failed to encode '%s' from %s to %s"),
|
2018-07-21 15:49:19 +08:00
|
|
|
path, default_encoding, enc);
|
2018-04-16 02:16:07 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_attach(buf, dst, dst_len, dst_len + 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
static int crlf_to_git(struct index_state *istate,
|
2017-06-13 06:13:53 +08:00
|
|
|
const char *path, const char *src, size_t len,
|
2011-05-10 04:12:57 +08:00
|
|
|
struct strbuf *buf,
|
2020-12-16 22:50:30 +08:00
|
|
|
enum convert_crlf_action crlf_action, int conv_flags)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
|
|
|
struct text_stat stats;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *dst;
|
2016-08-14 05:29:27 +08:00
|
|
|
int convert_crlf_into_lf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
if (crlf_action == CRLF_BINARY ||
|
2012-02-25 06:05:03 +08:00
|
|
|
(src && !len))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
2012-02-25 06:05:03 +08:00
|
|
|
/*
|
|
|
|
* If we are doing a dry-run and have no source buffer, there is
|
|
|
|
* nothing to analyze; we must assume we would convert.
|
|
|
|
*/
|
|
|
|
if (!buf && !src)
|
|
|
|
return 1;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
gather_stats(src, len, &stats);
|
2016-08-14 05:29:27 +08:00
|
|
|
/* Optimization: No CRLF? Nothing to convert, regardless. */
|
|
|
|
convert_crlf_into_lf = !!stats.crlf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
2019-01-24 21:12:41 +08:00
|
|
|
if (convert_is_binary(&stats))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2016-06-28 16:01:13 +08:00
|
|
|
/*
|
2016-12-01 01:02:32 +08:00
|
|
|
* If the file in the index has any CR in it, do not
|
|
|
|
* convert. This is the new safer autocrlf handling,
|
|
|
|
* unless we want to renormalize in a merge or
|
|
|
|
* cherry-pick.
|
2016-06-28 16:01:13 +08:00
|
|
|
*/
|
2018-01-14 06:49:31 +08:00
|
|
|
if ((!(conv_flags & CONV_EOL_RENORMALIZE)) &&
|
2017-11-26 20:20:52 +08:00
|
|
|
has_crlf_in_index(istate, path))
|
2016-08-14 05:29:27 +08:00
|
|
|
convert_crlf_into_lf = 0;
|
2007-04-16 04:35:45 +08:00
|
|
|
}
|
2018-01-14 06:49:31 +08:00
|
|
|
if (((conv_flags & CONV_EOL_RNDTRP_WARN) ||
|
|
|
|
((conv_flags & CONV_EOL_RNDTRP_DIE) && len))) {
|
2016-08-14 05:29:27 +08:00
|
|
|
struct text_stat new_stats;
|
|
|
|
memcpy(&new_stats, &stats, sizeof(new_stats));
|
|
|
|
/* simulate "git add" */
|
|
|
|
if (convert_crlf_into_lf) {
|
|
|
|
new_stats.lonelf += new_stats.crlf;
|
|
|
|
new_stats.crlf = 0;
|
|
|
|
}
|
|
|
|
/* simulate "git checkout" */
|
2019-01-24 21:12:41 +08:00
|
|
|
if (will_convert_lf_to_crlf(&new_stats, crlf_action)) {
|
2016-08-14 05:29:27 +08:00
|
|
|
new_stats.crlf += new_stats.lonelf;
|
|
|
|
new_stats.lonelf = 0;
|
|
|
|
}
|
2020-09-30 20:27:53 +08:00
|
|
|
check_global_conv_flags_eol(path, &stats, &new_stats, conv_flags);
|
2016-08-14 05:29:27 +08:00
|
|
|
}
|
|
|
|
if (!convert_crlf_into_lf)
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
return 0;
|
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
/*
|
|
|
|
* At this point all of our source analysis is done, and we are sure we
|
|
|
|
* would convert. If we are in dry-run mode, we can give an answer.
|
|
|
|
*/
|
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 16:11:59 +08:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst = buf->buf;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
2007-04-20 13:37:19 +08:00
|
|
|
/*
|
|
|
|
* If we guessed, we already know we rejected a file with
|
|
|
|
* lone CR, and we can strip a CR without looking at what
|
|
|
|
* follow it.
|
|
|
|
*/
|
2007-04-16 04:35:45 +08:00
|
|
|
do {
|
2007-04-19 08:05:03 +08:00
|
|
|
unsigned char c = *src++;
|
2007-04-16 04:35:45 +08:00
|
|
|
if (c != '\r')
|
2007-04-19 08:05:03 +08:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
} while (--len);
|
2007-04-16 04:35:45 +08:00
|
|
|
} else {
|
|
|
|
do {
|
2007-04-19 08:05:03 +08:00
|
|
|
unsigned char c = *src++;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
if (! (c == '\r' && (1 < len && *src == '\n')))
|
2007-04-19 08:05:03 +08:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
} while (--len);
|
2007-04-16 04:35:45 +08:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_setlen(buf, dst - buf->buf);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
|
|
|
|
2020-12-16 22:50:30 +08:00
|
|
|
static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf,
|
|
|
|
enum convert_crlf_action crlf_action)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *to_free = NULL;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
struct text_stat stats;
|
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
if (!len || output_eol(crlf_action) != EOL_CRLF)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
gather_stats(src, len, &stats);
|
2019-01-24 21:12:41 +08:00
|
|
|
if (!will_convert_lf_to_crlf(&stats, crlf_action))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 18:58:23 +08:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
|
2016-02-11 00:24:43 +08:00
|
|
|
strbuf_grow(buf, len + stats.lonelf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
for (;;) {
|
|
|
|
const char *nl = memchr(src, '\n', len);
|
|
|
|
if (!nl)
|
|
|
|
break;
|
|
|
|
if (nl > src && nl[-1] == '\r') {
|
|
|
|
strbuf_add(buf, src, nl + 1 - src);
|
|
|
|
} else {
|
|
|
|
strbuf_add(buf, src, nl - src);
|
|
|
|
strbuf_addstr(buf, "\r\n");
|
|
|
|
}
|
|
|
|
len -= nl + 1 - src;
|
|
|
|
src = nl + 1;
|
|
|
|
}
|
|
|
|
strbuf_add(buf, src, len);
|
|
|
|
|
|
|
|
free(to_free);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
2007-04-13 13:30:05 +08:00
|
|
|
|
2007-10-20 03:48:06 +08:00
|
|
|
struct filter_params {
|
|
|
|
const char *src;
|
2021-11-02 23:46:11 +08:00
|
|
|
size_t size;
|
2014-08-26 23:23:25 +08:00
|
|
|
int fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
const char *cmd;
|
2010-12-22 22:40:13 +08:00
|
|
|
const char *path;
|
2007-10-20 03:48:06 +08:00
|
|
|
};
|
|
|
|
|
2022-08-26 01:09:48 +08:00
|
|
|
static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Spawn cmd and feed the buffer contents through its stdin.
|
|
|
|
*/
|
2014-08-20 03:09:35 +08:00
|
|
|
struct child_process child_process = CHILD_PROCESS_INIT;
|
2007-10-20 03:48:06 +08:00
|
|
|
struct filter_params *params = (struct filter_params *)data;
|
2007-04-21 18:14:13 +08:00
|
|
|
int write_err, status;
|
2010-05-14 17:31:33 +08:00
|
|
|
|
2010-12-22 22:40:13 +08:00
|
|
|
/* apply % substitution to cmd */
|
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
struct strbuf_expand_dict_entry dict[] = {
|
|
|
|
{ "f", NULL, },
|
|
|
|
{ NULL, NULL, },
|
|
|
|
};
|
|
|
|
|
|
|
|
/* quote the path to preserve spaces, etc. */
|
|
|
|
sq_quote_buf(&path, params->path);
|
|
|
|
dict[0].value = path.buf;
|
|
|
|
|
|
|
|
/* expand all %f with the quoted path */
|
|
|
|
strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
|
|
|
|
strbuf_release(&path);
|
|
|
|
|
2020-08-27 06:25:03 +08:00
|
|
|
strvec_push(&child_process.args, cmd.buf);
|
2009-12-30 18:53:57 +08:00
|
|
|
child_process.use_shell = 1;
|
2007-10-20 03:47:55 +08:00
|
|
|
child_process.in = -1;
|
2010-02-06 04:57:38 +08:00
|
|
|
child_process.out = out;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2017-08-31 01:49:40 +08:00
|
|
|
if (start_command(&child_process)) {
|
|
|
|
strbuf_release(&cmd);
|
2018-07-21 15:49:29 +08:00
|
|
|
return error(_("cannot fork to run external filter '%s'"),
|
|
|
|
params->cmd);
|
2017-08-31 01:49:40 +08:00
|
|
|
}
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2012-02-21 04:53:37 +08:00
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
2014-08-26 23:23:25 +08:00
|
|
|
if (params->src) {
|
2015-05-20 02:08:23 +08:00
|
|
|
write_err = (write_in_full(child_process.in,
|
|
|
|
params->src, params->size) < 0);
|
|
|
|
if (errno == EPIPE)
|
|
|
|
write_err = 0;
|
2014-08-26 23:23:25 +08:00
|
|
|
} else {
|
|
|
|
write_err = copy_fd(params->fd, child_process.in);
|
2015-05-20 02:08:23 +08:00
|
|
|
if (write_err == COPY_WRITE_ERROR && errno == EPIPE)
|
|
|
|
write_err = 0;
|
2014-08-26 23:23:25 +08:00
|
|
|
}
|
|
|
|
|
2007-10-20 03:47:55 +08:00
|
|
|
if (close(child_process.in))
|
2007-04-21 18:14:13 +08:00
|
|
|
write_err = 1;
|
|
|
|
if (write_err)
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("cannot feed the input to external filter '%s'"),
|
|
|
|
params->cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2012-02-21 04:53:37 +08:00
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2007-04-21 18:14:13 +08:00
|
|
|
status = finish_command(&child_process);
|
|
|
|
if (status)
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("external filter '%s' failed %d"), params->cmd, status);
|
2010-12-22 22:40:13 +08:00
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
return (write_err || status);
|
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
static int apply_single_file_filter(const char *path, const char *src, size_t len, int fd,
|
2018-12-06 23:42:06 +08:00
|
|
|
struct strbuf *dst, const char *cmd)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Create a pipeline to have the command filter the buffer's
|
|
|
|
* contents.
|
|
|
|
*
|
|
|
|
* (child --> cmd) --> us
|
|
|
|
*/
|
2016-10-17 07:20:35 +08:00
|
|
|
int err = 0;
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf nbuf = STRBUF_INIT;
|
2007-10-20 03:48:06 +08:00
|
|
|
struct async async;
|
|
|
|
struct filter_params params;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2007-10-20 03:48:06 +08:00
|
|
|
memset(&async, 0, sizeof(async));
|
2014-08-26 23:23:25 +08:00
|
|
|
async.proc = filter_buffer_or_fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
async.data = ¶ms;
|
2010-02-06 04:57:38 +08:00
|
|
|
async.out = -1;
|
2007-10-20 03:48:06 +08:00
|
|
|
params.src = src;
|
|
|
|
params.size = len;
|
2014-08-26 23:23:25 +08:00
|
|
|
params.fd = fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
params.cmd = cmd;
|
2010-12-22 22:40:13 +08:00
|
|
|
params.path = path;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
|
|
|
fflush(NULL);
|
2007-10-20 03:48:06 +08:00
|
|
|
if (start_async(&async))
|
|
|
|
return 0; /* error was already reported */
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2019-03-08 03:56:57 +08:00
|
|
|
if (strbuf_read(&nbuf, async.out, 0) < 0) {
|
2018-07-21 15:49:29 +08:00
|
|
|
err = error(_("read from external filter '%s' failed"), cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2007-10-20 03:48:06 +08:00
|
|
|
if (close(async.out)) {
|
2018-07-21 15:49:29 +08:00
|
|
|
err = error(_("read from external filter '%s' failed"), cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2007-10-20 03:48:06 +08:00
|
|
|
if (finish_async(&async)) {
|
2018-07-21 15:49:29 +08:00
|
|
|
err = error(_("external filter '%s' failed"), cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:35 +08:00
|
|
|
if (!err) {
|
2007-10-05 16:11:59 +08:00
|
|
|
strbuf_swap(dst, &nbuf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
}
|
2007-10-05 16:11:59 +08:00
|
|
|
strbuf_release(&nbuf);
|
2016-10-17 07:20:35 +08:00
|
|
|
return !err;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
#define CAP_CLEAN (1u<<0)
|
|
|
|
#define CAP_SMUDGE (1u<<1)
|
2017-07-01 04:41:28 +08:00
|
|
|
#define CAP_DELAY (1u<<2)
|
2016-10-17 07:20:36 +08:00
|
|
|
|
2017-05-05 23:27:58 +08:00
|
|
|
struct cmd2process {
|
|
|
|
struct subprocess_entry subprocess; /* must be the first member! */
|
|
|
|
unsigned int supported_capabilities;
|
|
|
|
};
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static int subprocess_map_initialized;
|
|
|
|
static struct hashmap subprocess_map;
|
2016-10-17 07:20:37 +08:00
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
2017-07-27 02:17:29 +08:00
|
|
|
static int versions[] = {2, 0};
|
|
|
|
static struct subprocess_capability capabilities[] = {
|
2017-07-01 04:41:27 +08:00
|
|
|
{ "clean", CAP_CLEAN },
|
|
|
|
{ "smudge", CAP_SMUDGE },
|
2017-07-01 04:41:28 +08:00
|
|
|
{ "delay", CAP_DELAY },
|
2017-07-27 02:17:29 +08:00
|
|
|
{ NULL, 0 }
|
2017-07-01 04:41:27 +08:00
|
|
|
};
|
2017-07-27 02:17:29 +08:00
|
|
|
struct cmd2process *entry = (struct cmd2process *)subprocess;
|
|
|
|
return subprocess_handshake(subprocess, "git-filter", versions, NULL,
|
|
|
|
capabilities,
|
|
|
|
&entry->supported_capabilities);
|
2017-05-05 23:27:57 +08:00
|
|
|
}
|
|
|
|
|
2017-06-29 05:29:51 +08:00
|
|
|
static void handle_filter_error(const struct strbuf *filter_status,
|
|
|
|
struct cmd2process *entry,
|
2018-12-09 18:25:21 +08:00
|
|
|
const unsigned int wanted_capability)
|
|
|
|
{
|
2017-06-29 05:29:51 +08:00
|
|
|
if (!strcmp(filter_status->buf, "error"))
|
|
|
|
; /* The filter signaled a problem with the file. */
|
|
|
|
else if (!strcmp(filter_status->buf, "abort") && wanted_capability) {
|
|
|
|
/*
|
|
|
|
* The filter signaled a permanent problem. Don't try to filter
|
|
|
|
* files with the same command for the lifetime of the current
|
|
|
|
* Git process.
|
|
|
|
*/
|
|
|
|
entry->supported_capabilities &= ~wanted_capability;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Something went wrong with the protocol filter.
|
|
|
|
* Force shutdown and restart if another blob requires filtering.
|
|
|
|
*/
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("external filter '%s' failed"), entry->subprocess.cmd);
|
2017-06-29 05:29:51 +08:00
|
|
|
subprocess_stop(&subprocess_map, &entry->subprocess);
|
|
|
|
free(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
|
|
|
|
int fd, struct strbuf *dst, const char *cmd,
|
2017-07-01 04:41:28 +08:00
|
|
|
const unsigned int wanted_capability,
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
const struct checkout_metadata *meta,
|
2017-07-01 04:41:28 +08:00
|
|
|
struct delayed_checkout *dco)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
|
|
|
int err;
|
2017-07-01 04:41:28 +08:00
|
|
|
int can_delay = 0;
|
2016-10-17 07:20:37 +08:00
|
|
|
struct cmd2process *entry;
|
|
|
|
struct child_process *process;
|
|
|
|
struct strbuf nbuf = STRBUF_INIT;
|
|
|
|
struct strbuf filter_status = STRBUF_INIT;
|
|
|
|
const char *filter_type;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
if (!subprocess_map_initialized) {
|
|
|
|
subprocess_map_initialized = 1;
|
2017-07-01 08:28:33 +08:00
|
|
|
hashmap_init(&subprocess_map, cmd2process_cmp, NULL, 0);
|
2016-10-17 07:20:37 +08:00
|
|
|
entry = NULL;
|
|
|
|
} else {
|
2017-05-05 23:28:00 +08:00
|
|
|
entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fflush(NULL);
|
|
|
|
|
|
|
|
if (!entry) {
|
2017-05-05 23:27:59 +08:00
|
|
|
entry = xmalloc(sizeof(*entry));
|
|
|
|
entry->supported_capabilities = 0;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) {
|
2017-05-05 23:27:59 +08:00
|
|
|
free(entry);
|
2016-10-17 07:20:37 +08:00
|
|
|
return 0;
|
2017-05-05 23:27:59 +08:00
|
|
|
}
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
2017-05-05 23:27:58 +08:00
|
|
|
process = &entry->subprocess.process;
|
2016-10-17 07:20:37 +08:00
|
|
|
|
2017-06-29 05:29:50 +08:00
|
|
|
if (!(entry->supported_capabilities & wanted_capability))
|
2016-10-17 07:20:37 +08:00
|
|
|
return 0;
|
|
|
|
|
2017-06-29 05:29:50 +08:00
|
|
|
if (wanted_capability & CAP_CLEAN)
|
2016-10-17 07:20:37 +08:00
|
|
|
filter_type = "clean";
|
2017-06-29 05:29:50 +08:00
|
|
|
else if (wanted_capability & CAP_SMUDGE)
|
2016-10-17 07:20:37 +08:00
|
|
|
filter_type = "smudge";
|
|
|
|
else
|
2018-07-21 15:49:29 +08:00
|
|
|
die(_("unexpected filter type"));
|
2016-10-17 07:20:37 +08:00
|
|
|
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
|
|
assert(strlen(filter_type) < LARGE_PACKET_DATA_MAX - strlen("command=\n"));
|
|
|
|
err = packet_write_fmt_gently(process->in, "command=%s\n", filter_type);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = strlen(path) > LARGE_PACKET_DATA_MAX - strlen("pathname=\n");
|
|
|
|
if (err) {
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("path name too long for external filter"));
|
2016-10-17 07:20:37 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = packet_write_fmt_gently(process->in, "pathname=%s\n", path);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
if (meta && meta->refname) {
|
|
|
|
err = packet_write_fmt_gently(process->in, "ref=%s\n", meta->refname);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meta && !is_null_oid(&meta->treeish)) {
|
|
|
|
err = packet_write_fmt_gently(process->in, "treeish=%s\n", oid_to_hex(&meta->treeish));
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meta && !is_null_oid(&meta->blob)) {
|
|
|
|
err = packet_write_fmt_gently(process->in, "blob=%s\n", oid_to_hex(&meta->blob));
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2017-07-01 04:41:28 +08:00
|
|
|
if ((entry->supported_capabilities & CAP_DELAY) &&
|
|
|
|
dco && dco->state == CE_CAN_DELAY) {
|
|
|
|
can_delay = 1;
|
|
|
|
err = packet_write_fmt_gently(process->in, "can-delay=1\n");
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
err = packet_flush_gently(process->in);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (fd >= 0)
|
2021-03-16 05:08:19 +08:00
|
|
|
err = write_packetized_from_fd_no_flush(fd, process->in);
|
2016-10-17 07:20:37 +08:00
|
|
|
else
|
2021-03-16 05:08:19 +08:00
|
|
|
err = write_packetized_from_buf_no_flush(src, len, process->in);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = packet_flush_gently(process->in);
|
2016-10-17 07:20:37 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-05-05 23:28:02 +08:00
|
|
|
err = subprocess_read_status(process->out, &filter_status);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-07-01 04:41:28 +08:00
|
|
|
if (can_delay && !strcmp(filter_status.buf, "delayed")) {
|
|
|
|
string_list_insert(&dco->filters, cmd);
|
|
|
|
string_list_insert(&dco->paths, path);
|
|
|
|
} else {
|
|
|
|
/* The filter got the blob and wants to send us a response. */
|
|
|
|
err = strcmp(filter_status.buf, "success");
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2021-03-16 05:08:21 +08:00
|
|
|
err = read_packetized_to_strbuf(process->out, &nbuf,
|
|
|
|
PACKET_READ_GENTLE_ON_EOF) < 0;
|
2017-07-01 04:41:28 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = subprocess_read_status(process->out, &filter_status);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = strcmp(filter_status.buf, "success");
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
handle_filter_error(&filter_status, entry, wanted_capability);
|
|
|
|
else
|
|
|
|
strbuf_swap(dst, &nbuf);
|
|
|
|
strbuf_release(&nbuf);
|
2021-07-25 21:08:26 +08:00
|
|
|
strbuf_release(&filter_status);
|
2017-07-01 04:41:28 +08:00
|
|
|
return !err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int async_query_available_blobs(const char *cmd, struct string_list *available_paths)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
char *line;
|
|
|
|
struct cmd2process *entry;
|
|
|
|
struct child_process *process;
|
|
|
|
struct strbuf filter_status = STRBUF_INIT;
|
|
|
|
|
|
|
|
assert(subprocess_map_initialized);
|
|
|
|
entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
|
|
|
|
if (!entry) {
|
2018-07-21 15:49:29 +08:00
|
|
|
error(_("external filter '%s' is not available anymore although "
|
|
|
|
"not all paths have been filtered"), cmd);
|
2017-07-01 04:41:28 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
process = &entry->subprocess.process;
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
|
|
err = packet_write_fmt_gently(
|
|
|
|
process->in, "command=list_available_blobs\n");
|
2016-10-17 07:20:37 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-07-01 04:41:28 +08:00
|
|
|
err = packet_flush_gently(process->in);
|
2016-10-17 07:20:37 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-07-01 04:41:28 +08:00
|
|
|
while ((line = packet_read_line(process->out, NULL))) {
|
|
|
|
const char *path;
|
|
|
|
if (skip_prefix(line, "pathname=", &path))
|
|
|
|
string_list_insert(available_paths, xstrdup(path));
|
|
|
|
else
|
|
|
|
; /* ignore unknown keys */
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:28:02 +08:00
|
|
|
err = subprocess_read_status(process->out, &filter_status);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
err = strcmp(filter_status.buf, "success");
|
|
|
|
|
|
|
|
done:
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2017-06-29 05:29:51 +08:00
|
|
|
if (err)
|
2017-07-01 04:41:28 +08:00
|
|
|
handle_filter_error(&filter_status, entry, 0);
|
2021-07-25 21:08:26 +08:00
|
|
|
strbuf_release(&filter_status);
|
2016-10-17 07:20:37 +08:00
|
|
|
return !err;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct convert_driver {
|
|
|
|
const char *name;
|
|
|
|
struct convert_driver *next;
|
2008-07-05 13:24:42 +08:00
|
|
|
const char *smudge;
|
|
|
|
const char *clean;
|
2016-10-17 07:20:37 +08:00
|
|
|
const char *process;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
int required;
|
2007-04-21 18:14:13 +08:00
|
|
|
} *user_convert, **user_convert_tail;
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
static int apply_filter(const char *path, const char *src, size_t len,
|
|
|
|
int fd, struct strbuf *dst, struct convert_driver *drv,
|
2017-07-01 04:41:28 +08:00
|
|
|
const unsigned int wanted_capability,
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
const struct checkout_metadata *meta,
|
2017-07-01 04:41:28 +08:00
|
|
|
struct delayed_checkout *dco)
|
2016-10-17 07:20:36 +08:00
|
|
|
{
|
|
|
|
const char *cmd = NULL;
|
|
|
|
|
|
|
|
if (!drv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dst)
|
|
|
|
return 1;
|
|
|
|
|
2017-06-29 05:29:50 +08:00
|
|
|
if ((wanted_capability & CAP_CLEAN) && !drv->process && drv->clean)
|
2016-10-17 07:20:36 +08:00
|
|
|
cmd = drv->clean;
|
2017-06-29 05:29:50 +08:00
|
|
|
else if ((wanted_capability & CAP_SMUDGE) && !drv->process && drv->smudge)
|
2016-10-17 07:20:36 +08:00
|
|
|
cmd = drv->smudge;
|
|
|
|
|
|
|
|
if (cmd && *cmd)
|
|
|
|
return apply_single_file_filter(path, src, len, fd, dst, cmd);
|
2016-10-17 07:20:37 +08:00
|
|
|
else if (drv->process && *drv->process)
|
2017-07-01 04:41:28 +08:00
|
|
|
return apply_multi_file_filter(path, src, len, fd, dst,
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
drv->process, wanted_capability, meta, dco);
|
2016-10-17 07:20:36 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-26 01:09:48 +08:00
|
|
|
static int read_convert_config(const char *var, const char *value, void *cb UNUSED)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
2013-01-23 14:24:23 +08:00
|
|
|
const char *key, *name;
|
2020-04-11 03:44:28 +08:00
|
|
|
size_t namelen;
|
2007-04-21 18:14:13 +08:00
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* External conversion drivers are configured using
|
|
|
|
* "filter.<name>.variable".
|
|
|
|
*/
|
2013-01-23 14:24:23 +08:00
|
|
|
if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
|
2007-04-21 18:14:13 +08:00
|
|
|
return 0;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
|
|
|
break;
|
|
|
|
if (!drv) {
|
2021-03-14 00:17:22 +08:00
|
|
|
CALLOC_ARRAY(drv, 1);
|
2007-09-16 06:32:36 +08:00
|
|
|
drv->name = xmemdupz(name, namelen);
|
2007-04-21 18:14:13 +08:00
|
|
|
*user_convert_tail = drv;
|
|
|
|
user_convert_tail = &(drv->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* filter.<name>.smudge and filter.<name>.clean specifies
|
|
|
|
* the command line:
|
|
|
|
*
|
|
|
|
* command-line
|
|
|
|
*
|
|
|
|
* The command-line will not be interpolated in any way.
|
|
|
|
*/
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("smudge", key))
|
2008-07-05 13:24:42 +08:00
|
|
|
return git_config_string(&drv->smudge, var, value);
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("clean", key))
|
2008-07-05 13:24:42 +08:00
|
|
|
return git_config_string(&drv->clean, var, value);
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
if (!strcmp("process", key))
|
|
|
|
return git_config_string(&drv->process, var, value);
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("required", key)) {
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
drv->required = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-21 18:14:13 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-22 10:09:02 +08:00
|
|
|
static int count_ident(const char *cp, unsigned long size)
|
|
|
|
{
|
|
|
|
/*
|
2007-05-14 21:37:25 +08:00
|
|
|
* "$Id: 0000000000000000000000000000000000000000 $" <=> "$Id$"
|
2007-04-22 10:09:02 +08:00
|
|
|
*/
|
|
|
|
int cnt = 0;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch != '$')
|
|
|
|
continue;
|
2007-05-14 21:37:25 +08:00
|
|
|
if (size < 3)
|
2007-04-22 10:09:02 +08:00
|
|
|
break;
|
2007-05-14 21:37:25 +08:00
|
|
|
if (memcmp("Id", cp, 2))
|
2007-04-22 10:09:02 +08:00
|
|
|
continue;
|
2007-05-14 21:37:25 +08:00
|
|
|
ch = cp[2];
|
|
|
|
cp += 3;
|
|
|
|
size -= 3;
|
2007-04-22 10:09:02 +08:00
|
|
|
if (ch == '$')
|
2007-05-14 21:37:25 +08:00
|
|
|
cnt++; /* $Id$ */
|
2007-04-22 10:09:02 +08:00
|
|
|
if (ch != ':')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
2007-05-14 21:37:25 +08:00
|
|
|
* "$Id: ... "; scan up to the closing dollar sign and discard.
|
2007-04-22 10:09:02 +08:00
|
|
|
*/
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch == '$') {
|
|
|
|
cnt++;
|
|
|
|
break;
|
|
|
|
}
|
2010-04-06 20:46:37 +08:00
|
|
|
if (ch == '\n')
|
|
|
|
break;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:12:51 +08:00
|
|
|
static int ident_to_git(const char *src, size_t len,
|
2018-12-06 23:42:06 +08:00
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *dst, *dollar;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
2012-02-25 06:05:03 +08:00
|
|
|
if (!ident || (src && !count_ident(src, len)))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 16:11:59 +08:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst = buf->buf;
|
|
|
|
for (;;) {
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2011-08-30 04:06:04 +08:00
|
|
|
memmove(dst, src, dollar + 1 - src);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst += dollar + 1 - src;
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
|
|
|
|
if (len > 3 && !memcmp(src, "Id:", 3)) {
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2010-04-06 20:46:37 +08:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-05-14 21:37:25 +08:00
|
|
|
memcpy(dst, "Id$", 3);
|
|
|
|
dst += 3;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
}
|
2011-08-30 04:06:04 +08:00
|
|
|
memmove(dst, src, len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_setlen(buf, dst + len - buf->buf);
|
|
|
|
return 1;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:12:51 +08:00
|
|
|
static int ident_to_worktree(const char *src, size_t len,
|
2018-12-06 23:42:06 +08:00
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
2018-01-28 08:13:13 +08:00
|
|
|
struct object_id oid;
|
2010-04-06 20:46:38 +08:00
|
|
|
char *to_free = NULL, *dollar, *spc;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
int cnt;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
|
|
|
if (!ident)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
cnt = count_ident(src, len);
|
2007-04-22 10:09:02 +08:00
|
|
|
if (!cnt)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 18:58:23 +08:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
2022-02-05 07:48:32 +08:00
|
|
|
hash_object_file(the_hash_algo, src, len, OBJ_BLOB, &oid);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
2018-03-12 10:27:56 +08:00
|
|
|
strbuf_grow(buf, len + cnt * (the_hash_algo->hexsz + 3));
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
for (;;) {
|
|
|
|
/* step 1: run to the next '$' */
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
|
|
|
strbuf_add(buf, src, dollar + 1 - src);
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
|
|
|
|
if (len < 3 || memcmp("Id", src, 2))
|
2007-04-22 10:09:02 +08:00
|
|
|
continue;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 3: skip over Id$ or Id:xxxxx$ */
|
|
|
|
if (src[2] == '$') {
|
|
|
|
src += 3;
|
|
|
|
len -= 3;
|
|
|
|
} else if (src[2] == ':') {
|
|
|
|
/*
|
|
|
|
* It's possible that an expanded Id has crept its way into the
|
2010-04-06 20:46:38 +08:00
|
|
|
* repository, we cope with that by stripping the expansion out.
|
|
|
|
* This is probably not a good idea, since it will cause changes
|
|
|
|
* on checkout, which won't go away by stash, but let's keep it
|
|
|
|
* for git-style ids.
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
*/
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar) {
|
|
|
|
/* incomplete keyword, no more '$', so just quit the loop */
|
|
|
|
break;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
2010-04-06 20:46:37 +08:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-06 20:46:38 +08:00
|
|
|
spc = memchr(src + 4, ' ', dollar - src - 4);
|
|
|
|
if (spc && spc < dollar-1) {
|
|
|
|
/* There are spaces in unexpected places.
|
|
|
|
* This is probably an id from some other
|
|
|
|
* versioning system. Keep it for now.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
} else {
|
|
|
|
/* it wasn't a "Id$" or "Id:xxxx$" */
|
|
|
|
continue;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 4: substitute */
|
|
|
|
strbuf_addstr(buf, "Id: ");
|
2018-01-28 08:13:13 +08:00
|
|
|
strbuf_addstr(buf, oid_to_hex(&oid));
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_addstr(buf, " $");
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_add(buf, src, len);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
free(to_free);
|
|
|
|
return 1;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2018-04-16 02:16:07 +08:00
|
|
|
static const char *git_path_check_encoding(struct attr_check_item *check)
|
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_UNSET(value) || !strlen(value))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value) || ATTR_FALSE(value)) {
|
|
|
|
die(_("true/false are no valid working-tree-encodings"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't encode to the default encoding */
|
|
|
|
if (same_encoding(value, default_encoding))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-12-16 22:50:30 +08:00
|
|
|
static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
2007-04-21 14:44:02 +08:00
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value))
|
|
|
|
return CRLF_TEXT;
|
|
|
|
else if (ATTR_FALSE(value))
|
|
|
|
return CRLF_BINARY;
|
|
|
|
else if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "input"))
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
return CRLF_TEXT_INPUT;
|
2010-05-20 04:43:10 +08:00
|
|
|
else if (!strcmp(value, "auto"))
|
|
|
|
return CRLF_AUTO;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
return CRLF_UNDEFINED;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static enum eol git_path_check_eol(struct attr_check_item *check)
|
2010-05-20 04:43:10 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "lf"))
|
|
|
|
return EOL_LF;
|
|
|
|
else if (!strcmp(value, "crlf"))
|
|
|
|
return EOL_CRLF;
|
|
|
|
return EOL_UNSET;
|
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static struct convert_driver *git_path_check_convert(struct attr_check_item *check)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
|
|
|
|
return NULL;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strcmp(value, drv->name))
|
|
|
|
return drv;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static int git_path_check_ident(struct attr_check_item *check)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
return !!ATTR_TRUE(value);
|
|
|
|
}
|
|
|
|
|
2019-09-03 06:39:44 +08:00
|
|
|
static struct attr_check *check;
|
|
|
|
|
2021-04-30 12:50:26 +08:00
|
|
|
void convert_attrs(struct index_state *istate,
|
2020-12-16 22:50:30 +08:00
|
|
|
struct conv_attrs *ca, const char *path)
|
2011-05-10 02:23:04 +08:00
|
|
|
{
|
2018-09-13 03:32:02 +08:00
|
|
|
struct attr_check_item *ccheck = NULL;
|
2011-05-10 02:23:04 +08:00
|
|
|
|
2017-01-28 10:01:57 +08:00
|
|
|
if (!check) {
|
|
|
|
check = attr_check_initl("crlf", "ident", "filter",
|
2018-04-16 02:16:07 +08:00
|
|
|
"eol", "text", "working-tree-encoding",
|
|
|
|
NULL);
|
2011-05-10 02:23:04 +08:00
|
|
|
user_convert_tail = &user_convert;
|
|
|
|
git_config(read_convert_config, NULL);
|
|
|
|
}
|
2011-05-10 04:58:31 +08:00
|
|
|
|
2023-05-06 12:15:29 +08:00
|
|
|
git_check_attr(istate, path, check);
|
2018-09-13 03:32:02 +08:00
|
|
|
ccheck = check->items;
|
|
|
|
ca->crlf_action = git_path_check_crlf(ccheck + 4);
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED)
|
|
|
|
ca->crlf_action = git_path_check_crlf(ccheck + 0);
|
|
|
|
ca->ident = git_path_check_ident(ccheck + 1);
|
|
|
|
ca->drv = git_path_check_convert(ccheck + 2);
|
|
|
|
if (ca->crlf_action != CRLF_BINARY) {
|
|
|
|
enum eol eol_attr = git_path_check_eol(ccheck + 3);
|
|
|
|
if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
|
|
|
|
ca->crlf_action = CRLF_AUTO_INPUT;
|
|
|
|
else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
|
|
|
|
ca->crlf_action = CRLF_AUTO_CRLF;
|
|
|
|
else if (eol_attr == EOL_LF)
|
|
|
|
ca->crlf_action = CRLF_TEXT_INPUT;
|
|
|
|
else if (eol_attr == EOL_CRLF)
|
|
|
|
ca->crlf_action = CRLF_TEXT_CRLF;
|
2011-05-10 04:58:31 +08:00
|
|
|
}
|
2018-09-13 03:32:02 +08:00
|
|
|
ca->working_tree_encoding = git_path_check_encoding(ccheck + 5);
|
2017-08-22 01:43:45 +08:00
|
|
|
|
|
|
|
/* Save attr and make a decision for action */
|
|
|
|
ca->attr_action = ca->crlf_action;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (ca->crlf_action == CRLF_TEXT)
|
|
|
|
ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE)
|
|
|
|
ca->crlf_action = CRLF_BINARY;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_TRUE)
|
|
|
|
ca->crlf_action = CRLF_AUTO_CRLF;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_INPUT)
|
|
|
|
ca->crlf_action = CRLF_AUTO_INPUT;
|
2011-05-10 02:23:04 +08:00
|
|
|
}
|
|
|
|
|
2019-09-03 06:39:44 +08:00
|
|
|
void reset_parsed_attributes(void)
|
|
|
|
{
|
|
|
|
struct convert_driver *drv, *next;
|
|
|
|
|
|
|
|
attr_check_free(check);
|
|
|
|
check = NULL;
|
|
|
|
reset_merge_attributes();
|
|
|
|
|
|
|
|
for (drv = user_convert; drv; drv = next) {
|
|
|
|
next = drv->next;
|
|
|
|
free((void *)drv->name);
|
|
|
|
free(drv);
|
|
|
|
}
|
|
|
|
user_convert = NULL;
|
|
|
|
user_convert_tail = NULL;
|
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
int would_convert_to_git_filter_fd(struct index_state *istate, const char *path)
|
2014-08-26 23:23:25 +08:00
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
|
2018-08-14 00:14:21 +08:00
|
|
|
convert_attrs(istate, &ca, path);
|
2014-08-26 23:23:25 +08:00
|
|
|
if (!ca.drv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply a filter to an fd only if the filter is required to succeed.
|
|
|
|
* We must die if the filter fails, because the original data before
|
|
|
|
* filtering is not available.
|
|
|
|
*/
|
|
|
|
if (!ca.drv->required)
|
|
|
|
return 0;
|
|
|
|
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL, NULL);
|
2014-08-26 23:23:25 +08:00
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
const char *get_convert_attr_ascii(struct index_state *istate, const char *path)
|
2016-01-16 14:50:02 +08:00
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
|
2018-08-14 00:14:21 +08:00
|
|
|
convert_attrs(istate, &ca, path);
|
2016-02-06 00:13:23 +08:00
|
|
|
switch (ca.attr_action) {
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_UNDEFINED:
|
2016-01-16 14:50:02 +08:00
|
|
|
return "";
|
|
|
|
case CRLF_BINARY:
|
|
|
|
return "-text";
|
|
|
|
case CRLF_TEXT:
|
|
|
|
return "text";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_INPUT:
|
2016-01-16 14:50:02 +08:00
|
|
|
return "text eol=lf";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_CRLF:
|
|
|
|
return "text eol=crlf";
|
2016-01-16 14:50:02 +08:00
|
|
|
case CRLF_AUTO:
|
|
|
|
return "text=auto";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_CRLF:
|
2016-06-28 16:01:13 +08:00
|
|
|
return "text=auto eol=crlf";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_INPUT:
|
2016-06-28 16:01:13 +08:00
|
|
|
return "text=auto eol=lf";
|
2016-01-16 14:50:02 +08:00
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
int convert_to_git(struct index_state *istate,
|
2017-06-13 06:13:55 +08:00
|
|
|
const char *path, const char *src, size_t len,
|
2018-01-14 06:49:31 +08:00
|
|
|
struct strbuf *dst, int conv_flags)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
2011-05-10 04:58:31 +08:00
|
|
|
int ret = 0;
|
|
|
|
struct conv_attrs ca;
|
2007-04-21 14:44:02 +08:00
|
|
|
|
2018-08-14 00:14:21 +08:00
|
|
|
convert_attrs(istate, &ca, path);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL, NULL);
|
2016-10-17 07:20:36 +08:00
|
|
|
if (!ret && ca.drv && ca.drv->required)
|
2018-07-21 15:49:29 +08:00
|
|
|
die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
if (ret && dst) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2018-04-16 02:16:07 +08:00
|
|
|
|
|
|
|
ret |= encode_to_git(path, src, len, dst, ca.working_tree_encoding, conv_flags);
|
|
|
|
if (ret && dst) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
|
|
|
|
2018-01-14 06:49:31 +08:00
|
|
|
if (!(conv_flags & CONV_EOL_KEEP_CRLF)) {
|
|
|
|
ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags);
|
2017-08-13 16:51:04 +08:00
|
|
|
if (ret && dst) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2007-04-21 14:44:02 +08:00
|
|
|
}
|
2019-01-24 21:12:51 +08:00
|
|
|
return ret | ident_to_git(src, len, dst, ca.ident);
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
void convert_to_git_filter_fd(struct index_state *istate,
|
2017-06-13 06:13:54 +08:00
|
|
|
const char *path, int fd, struct strbuf *dst,
|
2018-01-14 06:49:31 +08:00
|
|
|
int conv_flags)
|
2014-08-26 23:23:25 +08:00
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
2018-08-14 00:14:21 +08:00
|
|
|
convert_attrs(istate, &ca, path);
|
2014-08-26 23:23:25 +08:00
|
|
|
|
|
|
|
assert(ca.drv);
|
|
|
|
|
convert: permit passing additional metadata to filter processes
There are a variety of situations where a filter process can make use of
some additional metadata. For example, some people find the ident
filter too limiting and would like to include the commit or the branch
in their smudged files. This information isn't available during
checkout as HEAD hasn't been updated at that point, and it wouldn't be
available in archives either.
Let's add a way to pass this metadata down to the filter. We pass the
blob we're operating on, the treeish (preferring the commit over the
tree if one exists), and the ref we're operating on. Note that we won't
pass this information in all cases, such as when renormalizing or when
we're performing diffs, since it doesn't make sense in those cases.
The data we currently get from the filter process looks like the
following:
command=smudge
pathname=git.c
0000
With this change, we'll get data more like this:
command=smudge
pathname=git.c
refname=refs/tags/v2.25.1
treeish=c522f061d551c9bb8684a7c3859b2ece4499b56b
blob=7be7ad34bd053884ec48923706e70c81719a8660
0000
There are a couple things to note about this approach. For operations
like checkout, treeish will always be a commit, since we cannot check
out individual trees, but for other operations, like archive, we can end
up operating on only a particular tree, so we'll provide only a tree as
the treeish. Similar comments apply for refname, since there are a
variety of cases in which we won't have a ref.
This commit wires up the code to print this information, but doesn't
pass any of it at this point. In a future commit, we'll have various
code paths pass the actual useful data down.
Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17 02:05:02 +08:00
|
|
|
if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL))
|
2018-07-21 15:49:29 +08:00
|
|
|
die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
|
2014-08-26 23:23:25 +08:00
|
|
|
|
2018-04-16 02:16:07 +08:00
|
|
|
encode_to_git(path, dst->buf, dst->len, dst, ca.working_tree_encoding, conv_flags);
|
2018-01-14 06:49:31 +08:00
|
|
|
crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
|
2019-01-24 21:12:51 +08:00
|
|
|
ident_to_git(dst->buf, dst->len, dst, ca.ident);
|
2014-08-26 23:23:25 +08:00
|
|
|
}
|
|
|
|
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
|
|
|
|
const char *path, const char *src,
|
|
|
|
size_t len, struct strbuf *dst,
|
|
|
|
int normalizing,
|
|
|
|
const struct checkout_metadata *meta,
|
|
|
|
struct delayed_checkout *dco)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
int ret = 0, ret_filter = 0;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
ret |= ident_to_worktree(src, len, dst, ca->ident);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
2010-07-03 03:20:49 +08:00
|
|
|
/*
|
|
|
|
* CRLF conversion can be skipped if normalizing, unless there
|
2016-10-17 07:20:37 +08:00
|
|
|
* is a smudge or process filter (even if the process filter doesn't
|
|
|
|
* support smudge). The filters might expect CRLFs.
|
2010-07-03 03:20:49 +08:00
|
|
|
*/
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) {
|
|
|
|
ret |= crlf_to_worktree(src, len, dst, ca->crlf_action);
|
2010-07-03 03:20:49 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
ret |= encode_to_worktree(path, src, len, dst, ca->working_tree_encoding);
|
2018-04-16 02:16:07 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
|
|
|
|
2017-07-01 04:41:28 +08:00
|
|
|
ret_filter = apply_filter(
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
path, src, len, -1, dst, ca->drv, CAP_SMUDGE, meta, dco);
|
|
|
|
if (!ret_filter && ca->drv && ca->drv->required)
|
|
|
|
die(_("%s: smudge filter %s failed"), path, ca->drv->name);
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
|
|
|
|
return ret | ret_filter;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
2010-07-03 03:20:47 +08:00
|
|
|
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
|
|
|
|
const char *path, const char *src,
|
|
|
|
size_t len, struct strbuf *dst,
|
|
|
|
const struct checkout_metadata *meta,
|
|
|
|
void *dco)
|
2017-07-01 04:41:28 +08:00
|
|
|
{
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
|
|
|
|
meta, dco);
|
2017-07-01 04:41:28 +08:00
|
|
|
}
|
|
|
|
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
int convert_to_working_tree_ca(const struct conv_attrs *ca,
|
|
|
|
const char *path, const char *src,
|
|
|
|
size_t len, struct strbuf *dst,
|
|
|
|
const struct checkout_metadata *meta)
|
2010-07-03 03:20:49 +08:00
|
|
|
{
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
|
|
|
|
meta, NULL);
|
2010-07-03 03:20:49 +08:00
|
|
|
}
|
|
|
|
|
2021-04-01 09:49:39 +08:00
|
|
|
int renormalize_buffer(struct index_state *istate, const char *path,
|
2017-06-13 06:13:56 +08:00
|
|
|
const char *src, size_t len, struct strbuf *dst)
|
2010-07-03 03:20:47 +08:00
|
|
|
{
|
convert: add [async_]convert_to_working_tree_ca() variants
Separate the attribute gathering from the actual conversion by adding
_ca() variants of the conversion functions. These variants receive a
precomputed 'struct conv_attrs', not relying, thus, on an index state.
They will be used in a future patch adding parallel checkout support,
for two reasons:
- We will already load the conversion attributes in checkout_entry(),
before conversion, to decide whether a path is eligible for parallel
checkout. Therefore, it would be wasteful to load them again later,
for the actual conversion.
- The parallel workers will be responsible for reading, converting and
writing blobs to the working tree. They won't have access to the main
process' index state, so they cannot load the attributes. Instead,
they will receive the preloaded ones and call the _ca() variant of
the conversion functions. Furthermore, the attributes machinery is
optimized to handle paths in sequential order, so it's better to leave
it for the main process, anyway.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-16 22:50:31 +08:00
|
|
|
struct conv_attrs ca;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
convert_attrs(istate, &ca, path);
|
|
|
|
ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1,
|
|
|
|
NULL, NULL);
|
2010-07-03 03:20:47 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2018-01-14 06:49:31 +08:00
|
|
|
return ret | convert_to_git(istate, path, src, len, dst, CONV_EOL_RENORMALIZE);
|
2010-07-03 03:20:47 +08:00
|
|
|
}
|
2011-05-13 05:31:08 +08:00
|
|
|
|
2011-05-21 05:33:31 +08:00
|
|
|
/*****************************************************************
|
|
|
|
*
|
2013-07-23 05:02:23 +08:00
|
|
|
* Streaming conversion support
|
2011-05-21 05:33:31 +08:00
|
|
|
*
|
|
|
|
*****************************************************************/
|
|
|
|
|
|
|
|
typedef int (*filter_fn)(struct stream_filter *,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p);
|
|
|
|
typedef void (*free_fn)(struct stream_filter *);
|
|
|
|
|
|
|
|
struct stream_filter_vtbl {
|
|
|
|
filter_fn filter;
|
|
|
|
free_fn free;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct stream_filter {
|
|
|
|
struct stream_filter_vtbl *vtbl;
|
|
|
|
};
|
|
|
|
|
2022-10-18 09:08:54 +08:00
|
|
|
static int null_filter_fn(struct stream_filter *filter UNUSED,
|
2011-05-21 05:33:31 +08:00
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-05-22 05:05:51 +08:00
|
|
|
size_t count;
|
|
|
|
|
|
|
|
if (!input)
|
|
|
|
return 0; /* we do not keep any states */
|
|
|
|
count = *isize_p;
|
2011-05-21 05:33:31 +08:00
|
|
|
if (*osize_p < count)
|
|
|
|
count = *osize_p;
|
|
|
|
if (count) {
|
|
|
|
memmove(output, input, count);
|
|
|
|
*isize_p -= count;
|
|
|
|
*osize_p -= count;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-18 09:08:54 +08:00
|
|
|
static void null_free_fn(struct stream_filter *filter UNUSED)
|
2011-05-21 05:33:31 +08:00
|
|
|
{
|
|
|
|
; /* nothing -- null instances are shared */
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl null_vtbl = {
|
2022-02-24 17:33:04 +08:00
|
|
|
.filter = null_filter_fn,
|
|
|
|
.free = null_free_fn,
|
2011-05-21 05:33:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter null_filter_singleton = {
|
2022-02-24 17:33:04 +08:00
|
|
|
.vtbl = &null_vtbl,
|
2011-05-21 05:33:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
int is_null_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
return filter == &null_filter_singleton;
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* LF-to-CRLF filter
|
|
|
|
*/
|
2011-11-28 18:48:12 +08:00
|
|
|
|
|
|
|
struct lf_to_crlf_filter {
|
|
|
|
struct stream_filter filter;
|
2011-12-17 07:44:18 +08:00
|
|
|
unsigned has_held:1;
|
|
|
|
char held;
|
2011-11-28 18:48:12 +08:00
|
|
|
};
|
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-11-28 18:48:12 +08:00
|
|
|
size_t count, o = 0;
|
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
|
|
|
|
|
2011-12-17 07:44:18 +08:00
|
|
|
/*
|
|
|
|
* We may be holding onto the CR to see if it is followed by a
|
|
|
|
* LF, in which case we would need to go to the main loop.
|
|
|
|
* Otherwise, just emit it to the output stream.
|
|
|
|
*/
|
|
|
|
if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) {
|
|
|
|
output[o++] = lf_to_crlf->held;
|
|
|
|
lf_to_crlf->has_held = 0;
|
2011-11-28 18:48:12 +08:00
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-12-17 06:39:37 +08:00
|
|
|
/* We are told to drain */
|
|
|
|
if (!input) {
|
|
|
|
*osize_p -= o;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
|
|
|
|
count = *isize_p;
|
2011-12-17 07:44:18 +08:00
|
|
|
if (count || lf_to_crlf->has_held) {
|
2011-11-28 18:48:12 +08:00
|
|
|
size_t i;
|
2011-12-17 07:44:18 +08:00
|
|
|
int was_cr = 0;
|
|
|
|
|
|
|
|
if (lf_to_crlf->has_held) {
|
|
|
|
was_cr = 1;
|
|
|
|
lf_to_crlf->has_held = 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
for (i = 0; o < *osize_p && i < count; i++) {
|
2011-05-21 07:47:56 +08:00
|
|
|
char ch = input[i];
|
2011-12-17 07:44:18 +08:00
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
if (ch == '\n') {
|
2011-11-28 18:48:12 +08:00
|
|
|
output[o++] = '\r';
|
2011-12-17 07:44:18 +08:00
|
|
|
} else if (was_cr) {
|
|
|
|
/*
|
|
|
|
* Previous round saw CR and it is not followed
|
|
|
|
* by a LF; emit the CR before processing the
|
|
|
|
* current character.
|
|
|
|
*/
|
|
|
|
output[o++] = '\r';
|
2011-05-21 07:47:56 +08:00
|
|
|
}
|
2011-12-17 07:44:18 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We may have consumed the last output slot,
|
|
|
|
* in which case we need to break out of this
|
|
|
|
* loop; hold the current character before
|
|
|
|
* returning.
|
|
|
|
*/
|
|
|
|
if (*osize_p <= o) {
|
|
|
|
lf_to_crlf->has_held = 1;
|
|
|
|
lf_to_crlf->held = ch;
|
|
|
|
continue; /* break but increment i */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == '\r') {
|
|
|
|
was_cr = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
was_cr = 0;
|
2011-05-21 07:47:56 +08:00
|
|
|
output[o++] = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
*osize_p -= o;
|
|
|
|
*isize_p -= i;
|
2011-12-17 07:44:18 +08:00
|
|
|
|
|
|
|
if (!lf_to_crlf->has_held && was_cr) {
|
|
|
|
lf_to_crlf->has_held = 1;
|
|
|
|
lf_to_crlf->held = '\r';
|
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
static void lf_to_crlf_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
|
2022-02-24 17:33:04 +08:00
|
|
|
.filter = lf_to_crlf_filter_fn,
|
|
|
|
.free = lf_to_crlf_free_fn,
|
2011-05-21 07:47:56 +08:00
|
|
|
};
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
static struct stream_filter *lf_to_crlf_filter(void)
|
|
|
|
{
|
2011-12-17 06:39:37 +08:00
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
|
|
|
|
return (struct stream_filter *)lf_to_crlf;
|
|
|
|
}
|
2011-05-21 09:28:00 +08:00
|
|
|
|
2011-05-22 09:28:41 +08:00
|
|
|
/*
|
|
|
|
* Cascade filter
|
|
|
|
*/
|
|
|
|
#define FILTER_BUFFER 1024
|
|
|
|
struct cascade_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct stream_filter *one;
|
|
|
|
struct stream_filter *two;
|
|
|
|
char buf[FILTER_BUFFER];
|
|
|
|
int end, ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int cascade_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *) filter;
|
|
|
|
size_t filled = 0;
|
|
|
|
size_t sz = *osize_p;
|
|
|
|
size_t to_feed, remaining;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* input -- (one) --> buf -- (two) --> output
|
|
|
|
*/
|
|
|
|
while (filled < sz) {
|
|
|
|
remaining = sz - filled;
|
|
|
|
|
|
|
|
/* do we already have something to feed two with? */
|
|
|
|
if (cas->ptr < cas->end) {
|
|
|
|
to_feed = cas->end - cas->ptr;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
cas->buf + cas->ptr, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->ptr += (cas->end - cas->ptr) - to_feed;
|
|
|
|
filled = sz - remaining;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* feed one from upstream and have it emit into our buffer */
|
|
|
|
to_feed = input ? *isize_p : 0;
|
|
|
|
if (input && !to_feed)
|
|
|
|
break;
|
|
|
|
remaining = sizeof(cas->buf);
|
|
|
|
if (stream_filter(cas->one,
|
|
|
|
input, &to_feed,
|
|
|
|
cas->buf, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->end = sizeof(cas->buf) - remaining;
|
|
|
|
cas->ptr = 0;
|
|
|
|
if (input) {
|
|
|
|
size_t fed = *isize_p - to_feed;
|
|
|
|
*isize_p -= fed;
|
|
|
|
input += fed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do we know that we drained one completely? */
|
|
|
|
if (input || cas->end)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* tell two to drain; we have nothing more to give it */
|
|
|
|
to_feed = 0;
|
|
|
|
remaining = sz - filled;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
NULL, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
if (remaining == (sz - filled))
|
|
|
|
break; /* completely drained two */
|
|
|
|
filled = sz - remaining;
|
|
|
|
}
|
|
|
|
*osize_p -= filled;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cascade_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *)filter;
|
|
|
|
free_stream_filter(cas->one);
|
|
|
|
free_stream_filter(cas->two);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl cascade_vtbl = {
|
2022-02-24 17:33:04 +08:00
|
|
|
.filter = cascade_filter_fn,
|
|
|
|
.free = cascade_free_fn,
|
2011-05-22 09:28:41 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter *cascade_filter(struct stream_filter *one,
|
|
|
|
struct stream_filter *two)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cascade;
|
|
|
|
|
|
|
|
if (!one || is_null_stream_filter(one))
|
|
|
|
return two;
|
|
|
|
if (!two || is_null_stream_filter(two))
|
|
|
|
return one;
|
|
|
|
|
|
|
|
cascade = xmalloc(sizeof(*cascade));
|
|
|
|
cascade->one = one;
|
|
|
|
cascade->two = two;
|
|
|
|
cascade->end = cascade->ptr = 0;
|
|
|
|
cascade->filter.vtbl = &cascade_vtbl;
|
|
|
|
return (struct stream_filter *)cascade;
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
/*
|
|
|
|
* ident filter
|
|
|
|
*/
|
|
|
|
#define IDENT_DRAINING (-1)
|
|
|
|
#define IDENT_SKIPPING (-2)
|
|
|
|
struct ident_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct strbuf left;
|
|
|
|
int state;
|
2018-03-12 10:27:56 +08:00
|
|
|
char ident[GIT_MAX_HEXSZ + 5]; /* ": x40 $" */
|
2011-05-21 09:28:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int is_foreign_ident(const char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-19 03:47:50 +08:00
|
|
|
if (!skip_prefix(str, "$Id: ", &str))
|
2011-05-21 09:28:00 +08:00
|
|
|
return 0;
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-19 03:47:50 +08:00
|
|
|
for (i = 0; str[i]; i++) {
|
2011-05-21 09:28:00 +08:00
|
|
|
if (isspace(str[i]) && str[i+1] != '$')
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
|
|
|
|
{
|
|
|
|
size_t to_drain = ident->left.len;
|
|
|
|
|
|
|
|
if (*osize_p < to_drain)
|
|
|
|
to_drain = *osize_p;
|
|
|
|
if (to_drain) {
|
|
|
|
memcpy(*output_p, ident->left.buf, to_drain);
|
|
|
|
strbuf_remove(&ident->left, 0, to_drain);
|
|
|
|
*output_p += to_drain;
|
|
|
|
*osize_p -= to_drain;
|
|
|
|
}
|
|
|
|
if (!ident->left.len)
|
|
|
|
ident->state = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ident_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
static const char head[] = "$Id";
|
|
|
|
|
|
|
|
if (!input) {
|
|
|
|
/* drain upon eof */
|
|
|
|
switch (ident->state) {
|
|
|
|
default:
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
consistently use "fallthrough" comments in switches
Gcc 7 adds -Wimplicit-fallthrough, which can warn when a
switch case falls through to the next case. The general idea
is that the compiler can't tell if this was intentional or
not, so you should annotate any intentional fall-throughs as
such, leaving it to complain about any unannotated ones.
There's a GNU __attribute__ which can be used for
annotation, but of course we'd have to #ifdef it away on
non-gcc compilers. Gcc will also recognize
specially-formatted comments, which matches our current
practice. Let's extend that practice to all of the
unannotated sites (which I did look over and verify that
they were behaving as intended).
Ideally in each case we'd actually give some reasons in the
comment about why we're falling through, or what we're
falling through to. And gcc does support that with
-Wimplicit-fallthrough=2, which relaxes the comment pattern
matching to anything that contains "fallthrough" (or a
variety of spelling variants). However, this isn't the
default for -Wimplicit-fallthrough, nor for -Wextra. In the
name of simplicity, it's probably better for us to support
the default level, which requires "fallthrough" to be the
only thing in the comment (modulo some window dressing like
"else" and some punctuation; see the gcc manual for the
complete set of patterns).
This patch suppresses all warnings due to
-Wimplicit-fallthrough. We might eventually want to add that
to the DEVELOPER Makefile knob, but we should probably wait
until gcc 7 is more widely adopted (since earlier versions
will complain about the unknown warning type).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-21 14:25:41 +08:00
|
|
|
/* fallthrough */
|
2011-05-21 09:28:00 +08:00
|
|
|
case IDENT_SKIPPING:
|
consistently use "fallthrough" comments in switches
Gcc 7 adds -Wimplicit-fallthrough, which can warn when a
switch case falls through to the next case. The general idea
is that the compiler can't tell if this was intentional or
not, so you should annotate any intentional fall-throughs as
such, leaving it to complain about any unannotated ones.
There's a GNU __attribute__ which can be used for
annotation, but of course we'd have to #ifdef it away on
non-gcc compilers. Gcc will also recognize
specially-formatted comments, which matches our current
practice. Let's extend that practice to all of the
unannotated sites (which I did look over and verify that
they were behaving as intended).
Ideally in each case we'd actually give some reasons in the
comment about why we're falling through, or what we're
falling through to. And gcc does support that with
-Wimplicit-fallthrough=2, which relaxes the comment pattern
matching to anything that contains "fallthrough" (or a
variety of spelling variants). However, this isn't the
default for -Wimplicit-fallthrough, nor for -Wextra. In the
name of simplicity, it's probably better for us to support
the default level, which requires "fallthrough" to be the
only thing in the comment (modulo some window dressing like
"else" and some punctuation; see the gcc manual for the
complete set of patterns).
This patch suppresses all warnings due to
-Wimplicit-fallthrough. We might eventually want to add that
to the DEVELOPER Makefile knob, but we should probably wait
until gcc 7 is more widely adopted (since earlier versions
will complain about the unknown warning type).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-21 14:25:41 +08:00
|
|
|
/* fallthrough */
|
2011-05-21 09:28:00 +08:00
|
|
|
case IDENT_DRAINING:
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*isize_p || (ident->state == IDENT_DRAINING)) {
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_DRAINING) {
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
if (!*osize_p)
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch = *(input++);
|
|
|
|
(*isize_p)--;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_SKIPPING) {
|
|
|
|
/*
|
|
|
|
* Skipping until '$' or LF, but keeping them
|
|
|
|
* in case it is a foreign ident.
|
|
|
|
*/
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
if (ch != '\n' && ch != '$')
|
|
|
|
continue;
|
|
|
|
if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
|
|
|
|
strbuf_setlen(&ident->left, sizeof(head) - 1);
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
}
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state < sizeof(head) &&
|
|
|
|
head[ident->state] == ch) {
|
|
|
|
ident->state++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state)
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
|
|
|
if (ident->state == sizeof(head) - 1) {
|
|
|
|
if (ch != ':' && ch != '$') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == ':') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_SKIPPING;
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
strbuf_release(&ident->left);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl ident_vtbl = {
|
2022-02-24 17:33:04 +08:00
|
|
|
.filter = ident_filter_fn,
|
|
|
|
.free = ident_free_fn,
|
2011-05-21 09:28:00 +08:00
|
|
|
};
|
|
|
|
|
2018-03-12 10:27:56 +08:00
|
|
|
static struct stream_filter *ident_filter(const struct object_id *oid)
|
2011-05-21 09:28:00 +08:00
|
|
|
{
|
|
|
|
struct ident_filter *ident = xmalloc(sizeof(*ident));
|
|
|
|
|
2015-09-25 05:06:08 +08:00
|
|
|
xsnprintf(ident->ident, sizeof(ident->ident),
|
2018-03-12 10:27:56 +08:00
|
|
|
": %s $", oid_to_hex(oid));
|
2011-05-21 09:28:00 +08:00
|
|
|
strbuf_init(&ident->left, 0);
|
|
|
|
ident->filter.vtbl = &ident_vtbl;
|
|
|
|
ident->state = 0;
|
|
|
|
return (struct stream_filter *)ident;
|
|
|
|
}
|
|
|
|
|
2011-05-13 05:31:08 +08:00
|
|
|
/*
|
2020-12-16 22:50:32 +08:00
|
|
|
* Return an appropriately constructed filter for the given ca, or NULL if
|
2011-05-21 05:33:31 +08:00
|
|
|
* the contents cannot be filtered without reading the whole thing
|
|
|
|
* in-core.
|
|
|
|
*
|
2020-02-12 02:56:18 +08:00
|
|
|
* Note that you would be crazy to set CRLF, smudge/clean or ident to a
|
2011-05-21 05:33:31 +08:00
|
|
|
* large binary blob you would want us not to slurp into the memory!
|
2011-05-13 05:31:08 +08:00
|
|
|
*/
|
2020-12-16 22:50:32 +08:00
|
|
|
struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
|
|
|
|
const struct object_id *oid)
|
2011-05-13 05:31:08 +08:00
|
|
|
{
|
2011-05-21 09:28:00 +08:00
|
|
|
struct stream_filter *filter = NULL;
|
2011-05-13 05:31:08 +08:00
|
|
|
|
2020-12-16 22:50:33 +08:00
|
|
|
if (classify_conv_attrs(ca) != CA_CLASS_STREAMABLE)
|
2018-04-16 02:16:07 +08:00
|
|
|
return NULL;
|
|
|
|
|
2020-12-16 22:50:32 +08:00
|
|
|
if (ca->ident)
|
2018-03-12 10:27:56 +08:00
|
|
|
filter = ident_filter(oid);
|
2011-05-13 05:31:08 +08:00
|
|
|
|
2020-12-16 22:50:32 +08:00
|
|
|
if (output_eol(ca->crlf_action) == EOL_CRLF)
|
2011-11-28 18:48:12 +08:00
|
|
|
filter = cascade_filter(filter, lf_to_crlf_filter());
|
2016-04-26 00:56:32 +08:00
|
|
|
else
|
|
|
|
filter = cascade_filter(filter, &null_filter_singleton);
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
return filter;
|
2011-05-21 05:33:31 +08:00
|
|
|
}
|
|
|
|
|
2021-04-30 12:50:26 +08:00
|
|
|
struct stream_filter *get_stream_filter(struct index_state *istate,
|
2020-12-16 22:50:32 +08:00
|
|
|
const char *path,
|
|
|
|
const struct object_id *oid)
|
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
convert_attrs(istate, &ca, path);
|
|
|
|
return get_stream_filter_ca(&ca, oid);
|
|
|
|
}
|
|
|
|
|
2011-05-21 05:33:31 +08:00
|
|
|
void free_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
filter->vtbl->free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
int stream_filter(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
|
2011-05-13 05:31:08 +08:00
|
|
|
}
|
2020-03-17 02:05:03 +08:00
|
|
|
|
|
|
|
void init_checkout_metadata(struct checkout_metadata *meta, const char *refname,
|
|
|
|
const struct object_id *treeish,
|
|
|
|
const struct object_id *blob)
|
|
|
|
{
|
|
|
|
memset(meta, 0, sizeof(*meta));
|
|
|
|
if (refname)
|
|
|
|
meta->refname = refname;
|
|
|
|
if (treeish)
|
|
|
|
oidcpy(&meta->treeish, treeish);
|
|
|
|
if (blob)
|
|
|
|
oidcpy(&meta->blob, blob);
|
|
|
|
}
|
|
|
|
|
|
|
|
void clone_checkout_metadata(struct checkout_metadata *dst,
|
|
|
|
const struct checkout_metadata *src,
|
|
|
|
const struct object_id *blob)
|
|
|
|
{
|
|
|
|
memcpy(dst, src, sizeof(*dst));
|
|
|
|
if (blob)
|
|
|
|
oidcpy(&dst->blob, blob);
|
|
|
|
}
|
2020-12-16 22:50:33 +08:00
|
|
|
|
|
|
|
enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca)
|
|
|
|
{
|
|
|
|
if (ca->drv) {
|
|
|
|
if (ca->drv->process)
|
|
|
|
return CA_CLASS_INCORE_PROCESS;
|
|
|
|
if (ca->drv->smudge || ca->drv->clean)
|
|
|
|
return CA_CLASS_INCORE_FILTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ca->working_tree_encoding)
|
|
|
|
return CA_CLASS_INCORE;
|
|
|
|
|
|
|
|
if (ca->crlf_action == CRLF_AUTO || ca->crlf_action == CRLF_AUTO_CRLF)
|
|
|
|
return CA_CLASS_INCORE;
|
|
|
|
|
|
|
|
return CA_CLASS_STREAMABLE;
|
|
|
|
}
|