Coverage Report

Created: 2025-12-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/convert.c
Line
Count
Source
1
#define USE_THE_REPOSITORY_VARIABLE
2
#define DISABLE_SIGN_COMPARE_WARNINGS
3
4
#include "git-compat-util.h"
5
#include "advice.h"
6
#include "config.h"
7
#include "convert.h"
8
#include "copy.h"
9
#include "gettext.h"
10
#include "hex.h"
11
#include "object-file.h"
12
#include "attr.h"
13
#include "run-command.h"
14
#include "quote.h"
15
#include "read-cache-ll.h"
16
#include "sigchain.h"
17
#include "pkt-line.h"
18
#include "sub-process.h"
19
#include "trace.h"
20
#include "utf8.h"
21
#include "merge-ll.h"
22
23
/*
24
 * convert.c - convert a file when checking it out and checking it in.
25
 *
26
 * This should use the pathname to decide on whether it wants to do some
27
 * more interesting conversions (automatic gzip/unzip, general format
28
 * conversions etc etc), but by default it just does automatic CRLF<->LF
29
 * translation when the "text" attribute or "auto_crlf" option is set.
30
 */
31
32
/* Stat bits: When BIN is set, the txt bits are unset */
33
0
#define CONVERT_STAT_BITS_TXT_LF    0x1
34
0
#define CONVERT_STAT_BITS_TXT_CRLF  0x2
35
0
#define CONVERT_STAT_BITS_BIN       0x4
36
37
struct text_stat {
38
  /* NUL, CR, LF and CRLF counts */
39
  unsigned nul, lonecr, lonelf, crlf;
40
41
  /* These are just approximations! */
42
  unsigned printable, nonprintable;
43
};
44
45
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
46
0
{
47
0
  unsigned long i;
48
49
0
  memset(stats, 0, sizeof(*stats));
50
51
0
  for (i = 0; i < size; i++) {
52
0
    unsigned char c = buf[i];
53
0
    if (c == '\r') {
54
0
      if (i+1 < size && buf[i+1] == '\n') {
55
0
        stats->crlf++;
56
0
        i++;
57
0
      } else
58
0
        stats->lonecr++;
59
0
      continue;
60
0
    }
61
0
    if (c == '\n') {
62
0
      stats->lonelf++;
63
0
      continue;
64
0
    }
65
0
    if (c == 127)
66
      /* DEL */
67
0
      stats->nonprintable++;
68
0
    else if (c < 32) {
69
0
      switch (c) {
70
        /* BS, HT, ESC and FF */
71
0
      case '\b': case '\t': case '\033': case '\014':
72
0
        stats->printable++;
73
0
        break;
74
0
      case 0:
75
0
        stats->nul++;
76
        /* fall through */
77
0
      default:
78
0
        stats->nonprintable++;
79
0
      }
80
0
    }
81
0
    else
82
0
      stats->printable++;
83
0
  }
84
85
  /* If file ends with EOF then don't count this EOF as non-printable. */
86
0
  if (size >= 1 && buf[size-1] == '\032')
87
0
    stats->nonprintable--;
88
0
}
89
90
/*
91
 * The same heuristics as diff.c::mmfile_is_binary()
92
 * We treat files with bare CR as binary
93
 */
94
static int convert_is_binary(const struct text_stat *stats)
95
0
{
96
0
  if (stats->lonecr)
97
0
    return 1;
98
0
  if (stats->nul)
99
0
    return 1;
100
0
  if ((stats->printable >> 7) < stats->nonprintable)
101
0
    return 1;
102
0
  return 0;
103
0
}
104
105
static unsigned int gather_convert_stats(const char *data, unsigned long size)
106
0
{
107
0
  struct text_stat stats;
108
0
  int ret = 0;
109
0
  if (!data || !size)
110
0
    return 0;
111
0
  gather_stats(data, size, &stats);
112
0
  if (convert_is_binary(&stats))
113
0
    ret |= CONVERT_STAT_BITS_BIN;
114
0
  if (stats.crlf)
115
0
    ret |= CONVERT_STAT_BITS_TXT_CRLF;
116
0
  if (stats.lonelf)
117
0
    ret |=  CONVERT_STAT_BITS_TXT_LF;
118
119
0
  return ret;
120
0
}
121
122
static const char *gather_convert_stats_ascii(const char *data, unsigned long size)
123
0
{
124
0
  unsigned int convert_stats = gather_convert_stats(data, size);
125
126
0
  if (convert_stats & CONVERT_STAT_BITS_BIN)
127
0
    return "-text";
128
0
  switch (convert_stats) {
129
0
  case CONVERT_STAT_BITS_TXT_LF:
130
0
    return "lf";
131
0
  case CONVERT_STAT_BITS_TXT_CRLF:
132
0
    return "crlf";
133
0
  case CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF:
134
0
    return "mixed";
135
0
  default:
136
0
    return "none";
137
0
  }
138
0
}
139
140
const char *get_cached_convert_stats_ascii(struct index_state *istate,
141
             const char *path)
142
0
{
143
0
  const char *ret;
144
0
  unsigned long sz;
145
0
  void *data = read_blob_data_from_index(istate, path, &sz);
146
0
  ret = gather_convert_stats_ascii(data, sz);
147
0
  free(data);
148
0
  return ret;
149
0
}
150
151
const char *get_wt_convert_stats_ascii(const char *path)
152
0
{
153
0
  const char *ret = "";
154
0
  struct strbuf sb = STRBUF_INIT;
155
0
  if (strbuf_read_file(&sb, path, 0) >= 0)
156
0
    ret = gather_convert_stats_ascii(sb.buf, sb.len);
157
0
  strbuf_release(&sb);
158
0
  return ret;
159
0
}
160
161
static int text_eol_is_crlf(void)
162
{
163
  if (auto_crlf == AUTO_CRLF_TRUE)
164
    return 1;
165
  else if (auto_crlf == AUTO_CRLF_INPUT)
166
    return 0;
167
  if (core_eol == EOL_CRLF)
168
    return 1;
169
  if (core_eol == EOL_UNSET && EOL_NATIVE == EOL_CRLF)
170
    return 1;
171
  return 0;
172
}
173
174
static enum eol output_eol(enum convert_crlf_action crlf_action)
175
0
{
176
0
  switch (crlf_action) {
177
0
  case CRLF_BINARY:
178
0
    return EOL_UNSET;
179
0
  case CRLF_TEXT_CRLF:
180
0
    return EOL_CRLF;
181
0
  case CRLF_TEXT_INPUT:
182
0
    return EOL_LF;
183
0
  case CRLF_UNDEFINED:
184
0
  case CRLF_AUTO_CRLF:
185
0
    return EOL_CRLF;
186
0
  case CRLF_AUTO_INPUT:
187
0
    return EOL_LF;
188
0
  case CRLF_TEXT:
189
0
  case CRLF_AUTO:
190
    /* fall through */
191
0
    return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
192
0
  }
193
0
  warning(_("illegal crlf_action %d"), (int)crlf_action);
194
0
  return core_eol;
195
0
}
196
197
static void check_global_conv_flags_eol(const char *path,
198
          struct text_stat *old_stats, struct text_stat *new_stats,
199
          int conv_flags)
200
0
{
201
0
  if (old_stats->crlf && !new_stats->crlf ) {
202
    /*
203
     * CRLFs would not be restored by checkout
204
     */
205
0
    if (conv_flags & CONV_EOL_RNDTRP_DIE)
206
0
      die(_("CRLF would be replaced by LF in %s"), path);
207
0
    else if (conv_flags & CONV_EOL_RNDTRP_WARN)
208
0
      warning(_("in the working copy of '%s', CRLF will be"
209
0
          " replaced by LF the next time Git touches"
210
0
          " it"), path);
211
0
  } else if (old_stats->lonelf && !new_stats->lonelf ) {
212
    /*
213
     * CRLFs would be added by checkout
214
     */
215
0
    if (conv_flags & CONV_EOL_RNDTRP_DIE)
216
0
      die(_("LF would be replaced by CRLF in %s"), path);
217
0
    else if (conv_flags & CONV_EOL_RNDTRP_WARN)
218
0
      warning(_("in the working copy of '%s', LF will be"
219
0
          " replaced by CRLF the next time Git touches"
220
0
          " it"), path);
221
0
  }
222
0
}
223
224
static int has_crlf_in_index(struct index_state *istate, const char *path)
225
0
{
226
0
  unsigned long sz;
227
0
  void *data;
228
0
  const char *crp;
229
0
  int has_crlf = 0;
230
231
0
  data = read_blob_data_from_index(istate, path, &sz);
232
0
  if (!data)
233
0
    return 0;
234
235
0
  crp = memchr(data, '\r', sz);
236
0
  if (crp) {
237
0
    unsigned int ret_stats;
238
0
    ret_stats = gather_convert_stats(data, sz);
239
0
    if (!(ret_stats & CONVERT_STAT_BITS_BIN) &&
240
0
        (ret_stats & CONVERT_STAT_BITS_TXT_CRLF))
241
0
      has_crlf = 1;
242
0
  }
243
0
  free(data);
244
0
  return has_crlf;
245
0
}
246
247
static int will_convert_lf_to_crlf(struct text_stat *stats,
248
           enum convert_crlf_action crlf_action)
249
0
{
250
0
  if (output_eol(crlf_action) != EOL_CRLF)
251
0
    return 0;
252
  /* No "naked" LF? Nothing to convert, regardless. */
253
0
  if (!stats->lonelf)
254
0
    return 0;
255
256
0
  if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
257
    /* If we have any CR or CRLF line endings, we do not touch it */
258
    /* This is the new safer autocrlf-handling */
259
0
    if (stats->lonecr || stats->crlf)
260
0
      return 0;
261
262
0
    if (convert_is_binary(stats))
263
0
      return 0;
264
0
  }
265
0
  return 1;
266
267
0
}
268
269
static int validate_encoding(const char *path, const char *enc,
270
          const char *data, size_t len, int die_on_error)
271
0
{
272
0
  const char *stripped;
273
274
  /* We only check for UTF here as UTF?? can be an alias for UTF-?? */
275
0
  if (skip_iprefix(enc, "UTF", &stripped)) {
276
0
    skip_prefix(stripped, "-", &stripped);
277
278
    /*
279
     * Check for detectable errors in UTF encodings
280
     */
281
0
    if (has_prohibited_utf_bom(enc, data, len)) {
282
0
      const char *error_msg = _(
283
0
        "BOM is prohibited in '%s' if encoded as %s");
284
      /*
285
       * This advice is shown for UTF-??BE and UTF-??LE encodings.
286
       * We cut off the last two characters of the encoding name
287
       * to generate the encoding name suitable for BOMs.
288
       */
289
0
      const char *advise_msg = _(
290
0
        "The file '%s' contains a byte order "
291
0
        "mark (BOM). Please use UTF-%.*s as "
292
0
        "working-tree-encoding.");
293
0
      int stripped_len = strlen(stripped) - strlen("BE");
294
0
      advise(advise_msg, path, stripped_len, stripped);
295
0
      if (die_on_error)
296
0
        die(error_msg, path, enc);
297
0
      else {
298
0
        return error(error_msg, path, enc);
299
0
      }
300
301
0
    } else if (is_missing_required_utf_bom(enc, data, len)) {
302
0
      const char *error_msg = _(
303
0
        "BOM is required in '%s' if encoded as %s");
304
0
      const char *advise_msg = _(
305
0
        "The file '%s' is missing a byte order "
306
0
        "mark (BOM). Please use UTF-%sBE or UTF-%sLE "
307
0
        "(depending on the byte order) as "
308
0
        "working-tree-encoding.");
309
0
      advise(advise_msg, path, stripped, stripped);
310
0
      if (die_on_error)
311
0
        die(error_msg, path, enc);
312
0
      else {
313
0
        return error(error_msg, path, enc);
314
0
      }
315
0
    }
316
317
0
  }
318
0
  return 0;
319
0
}
320
321
static void trace_encoding(const char *context, const char *path,
322
         const char *encoding, const char *buf, size_t len)
323
0
{
324
0
  static struct trace_key coe = TRACE_KEY_INIT(WORKING_TREE_ENCODING);
325
0
  struct strbuf trace = STRBUF_INIT;
326
0
  int i;
327
328
0
  if (!trace_want(&coe))
329
0
    return;
330
331
0
  strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding);
332
0
  for (i = 0; i < len && buf; ++i) {
333
0
    strbuf_addf(
334
0
      &trace, "| \033[2m%2i:\033[0m %2x \033[2m%c\033[0m%c",
335
0
      i,
336
0
      (unsigned char) buf[i],
337
0
      (buf[i] > 32 && buf[i] < 127 ? buf[i] : ' '),
338
0
      ((i+1) % 8 && (i+1) < len ? ' ' : '\n')
339
0
    );
340
0
  }
341
0
  strbuf_addchars(&trace, '\n', 1);
342
343
0
  trace_strbuf(&coe, &trace);
344
0
  strbuf_release(&trace);
345
0
}
346
347
static int check_roundtrip(const char *enc_name)
348
0
{
349
  /*
350
   * check_roundtrip_encoding contains a string of comma and/or
351
   * space separated encodings (eg. "UTF-16, ASCII, CP1125").
352
   * Search for the given encoding in that string.
353
   */
354
0
  const char *encoding = check_roundtrip_encoding ?
355
0
    check_roundtrip_encoding : "SHIFT-JIS";
356
0
  const char *found = strcasestr(encoding, enc_name);
357
0
  const char *next;
358
0
  int len;
359
0
  if (!found)
360
0
    return 0;
361
0
  next = found + strlen(enc_name);
362
0
  len = strlen(encoding);
363
0
  return (found && (
364
      /*
365
       * Check that the found encoding is at the beginning of
366
       * encoding or that it is prefixed with a space or
367
       * comma.
368
       */
369
0
      found == encoding || (
370
0
        (isspace(found[-1]) || found[-1] == ',')
371
0
      )
372
0
    ) && (
373
      /*
374
       * Check that the found encoding is at the end of
375
       * encoding or that it is suffixed with a space
376
       * or comma.
377
       */
378
0
      next == encoding + len || (
379
0
        next < encoding + len &&
380
0
        (isspace(next[0]) || next[0] == ',')
381
0
      )
382
0
    ));
383
0
}
384
385
static const char *default_encoding = "UTF-8";
386
387
static int encode_to_git(const char *path, const char *src, size_t src_len,
388
       struct strbuf *buf, const char *enc, int conv_flags)
389
0
{
390
0
  char *dst;
391
0
  size_t dst_len;
392
0
  int die_on_error = conv_flags & CONV_WRITE_OBJECT;
393
394
  /*
395
   * No encoding is specified or there is nothing to encode.
396
   * Tell the caller that the content was not modified.
397
   */
398
0
  if (!enc || (src && !src_len))
399
0
    return 0;
400
401
  /*
402
   * Looks like we got called from "would_convert_to_git()".
403
   * This means Git wants to know if it would encode (= modify!)
404
   * the content. Let's answer with "yes", since an encoding was
405
   * specified.
406
   */
407
0
  if (!buf && !src)
408
0
    return 1;
409
410
0
  if (validate_encoding(path, enc, src, src_len, die_on_error))
411
0
    return 0;
412
413
0
  trace_encoding("source", path, enc, src, src_len);
414
0
  dst = reencode_string_len(src, src_len, default_encoding, enc,
415
0
          &dst_len);
416
0
  if (!dst) {
417
    /*
418
     * We could add the blob "as-is" to Git. However, on checkout
419
     * we would try to re-encode to the original encoding. This
420
     * would fail and we would leave the user with a messed-up
421
     * working tree. Let's try to avoid this by screaming loud.
422
     */
423
0
    const char* msg = _("failed to encode '%s' from %s to %s");
424
0
    if (die_on_error)
425
0
      die(msg, path, enc, default_encoding);
426
0
    else {
427
0
      error(msg, path, enc, default_encoding);
428
0
      return 0;
429
0
    }
430
0
  }
431
0
  trace_encoding("destination", path, default_encoding, dst, dst_len);
432
433
  /*
434
   * UTF supports lossless conversion round tripping [1] and conversions
435
   * between UTF and other encodings are mostly round trip safe as
436
   * Unicode aims to be a superset of all other character encodings.
437
   * However, certain encodings (e.g. SHIFT-JIS) are known to have round
438
   * trip issues [2]. Check the round trip conversion for all encodings
439
   * listed in core.checkRoundtripEncoding.
440
   *
441
   * The round trip check is only performed if content is written to Git.
442
   * This ensures that no information is lost during conversion to/from
443
   * the internal UTF-8 representation.
444
   *
445
   * Please note, the code below is not tested because I was not able to
446
   * generate a faulty round trip without an iconv error. Iconv errors
447
   * are already caught above.
448
   *
449
   * [1] http://unicode.org/faq/utf_bom.html#gen2
450
   * [2] https://support.microsoft.com/en-us/help/170559/prb-conversion-problem-between-shift-jis-and-unicode
451
   */
452
0
  if (die_on_error && check_roundtrip(enc)) {
453
0
    char *re_src;
454
0
    size_t re_src_len;
455
456
0
    re_src = reencode_string_len(dst, dst_len,
457
0
               enc, default_encoding,
458
0
               &re_src_len);
459
460
0
    trace_printf("Checking roundtrip encoding for %s...\n", enc);
461
0
    trace_encoding("reencoded source", path, enc,
462
0
             re_src, re_src_len);
463
464
0
    if (!re_src || src_len != re_src_len ||
465
0
        memcmp(src, re_src, src_len)) {
466
0
      const char* msg = _("encoding '%s' from %s to %s and "
467
0
              "back is not the same");
468
0
      die(msg, path, enc, default_encoding);
469
0
    }
470
471
0
    free(re_src);
472
0
  }
473
474
0
  strbuf_attach(buf, dst, dst_len, dst_len + 1);
475
0
  return 1;
476
0
}
477
478
static int encode_to_worktree(const char *path, const char *src, size_t src_len,
479
            struct strbuf *buf, const char *enc)
480
0
{
481
0
  char *dst;
482
0
  size_t dst_len;
483
484
  /*
485
   * No encoding is specified or there is nothing to encode.
486
   * Tell the caller that the content was not modified.
487
   */
488
0
  if (!enc || (src && !src_len))
489
0
    return 0;
490
491
0
  dst = reencode_string_len(src, src_len, enc, default_encoding,
492
0
          &dst_len);
493
0
  if (!dst) {
494
0
    error(_("failed to encode '%s' from %s to %s"),
495
0
          path, default_encoding, enc);
496
0
    return 0;
497
0
  }
498
499
0
  strbuf_attach(buf, dst, dst_len, dst_len + 1);
500
0
  return 1;
501
0
}
502
503
static int crlf_to_git(struct index_state *istate,
504
           const char *path, const char *src, size_t len,
505
           struct strbuf *buf,
506
           enum convert_crlf_action crlf_action, int conv_flags)
507
0
{
508
0
  struct text_stat stats;
509
0
  char *dst;
510
0
  int convert_crlf_into_lf;
511
512
0
  if (crlf_action == CRLF_BINARY ||
513
0
      (src && !len))
514
0
    return 0;
515
516
  /*
517
   * If we are doing a dry-run and have no source buffer, there is
518
   * nothing to analyze; we must assume we would convert.
519
   */
520
0
  if (!buf && !src)
521
0
    return 1;
522
523
0
  gather_stats(src, len, &stats);
524
  /* Optimization: No CRLF? Nothing to convert, regardless. */
525
0
  convert_crlf_into_lf = !!stats.crlf;
526
527
0
  if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
528
0
    if (convert_is_binary(&stats))
529
0
      return 0;
530
    /*
531
     * If the file in the index has any CR in it, do not
532
     * convert.  This is the new safer autocrlf handling,
533
     * unless we want to renormalize in a merge or
534
     * cherry-pick.
535
     */
536
0
    if ((!(conv_flags & CONV_EOL_RENORMALIZE)) &&
537
0
        has_crlf_in_index(istate, path))
538
0
      convert_crlf_into_lf = 0;
539
0
  }
540
0
  if (((conv_flags & CONV_EOL_RNDTRP_WARN) ||
541
0
       ((conv_flags & CONV_EOL_RNDTRP_DIE) && len))) {
542
0
    struct text_stat new_stats;
543
0
    memcpy(&new_stats, &stats, sizeof(new_stats));
544
    /* simulate "git add" */
545
0
    if (convert_crlf_into_lf) {
546
0
      new_stats.lonelf += new_stats.crlf;
547
0
      new_stats.crlf = 0;
548
0
    }
549
    /* simulate "git checkout" */
550
0
    if (will_convert_lf_to_crlf(&new_stats, crlf_action)) {
551
0
      new_stats.crlf += new_stats.lonelf;
552
0
      new_stats.lonelf = 0;
553
0
    }
554
0
    check_global_conv_flags_eol(path, &stats, &new_stats, conv_flags);
555
0
  }
556
0
  if (!convert_crlf_into_lf)
557
0
    return 0;
558
559
  /*
560
   * At this point all of our source analysis is done, and we are sure we
561
   * would convert. If we are in dry-run mode, we can give an answer.
562
   */
563
0
  if (!buf)
564
0
    return 1;
565
566
  /* only grow if not in place */
567
0
  if (strbuf_avail(buf) + buf->len < len)
568
0
    strbuf_grow(buf, len - buf->len);
569
0
  dst = buf->buf;
570
0
  if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
571
    /*
572
     * If we guessed, we already know we rejected a file with
573
     * lone CR, and we can strip a CR without looking at what
574
     * follow it.
575
     */
576
0
    do {
577
0
      unsigned char c = *src++;
578
0
      if (c != '\r')
579
0
        *dst++ = c;
580
0
    } while (--len);
581
0
  } else {
582
0
    do {
583
0
      unsigned char c = *src++;
584
0
      if (! (c == '\r' && (1 < len && *src == '\n')))
585
0
        *dst++ = c;
586
0
    } while (--len);
587
0
  }
588
0
  strbuf_setlen(buf, dst - buf->buf);
589
0
  return 1;
590
0
}
591
592
static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf,
593
          enum convert_crlf_action crlf_action)
594
0
{
595
0
  char *to_free = NULL;
596
0
  struct text_stat stats;
597
598
0
  if (!len || output_eol(crlf_action) != EOL_CRLF)
599
0
    return 0;
600
601
0
  gather_stats(src, len, &stats);
602
0
  if (!will_convert_lf_to_crlf(&stats, crlf_action))
603
0
    return 0;
604
605
  /* are we "faking" in place editing ? */
606
0
  if (src == buf->buf)
607
0
    to_free = strbuf_detach(buf, NULL);
608
609
0
  strbuf_grow(buf, len + stats.lonelf);
610
0
  for (;;) {
611
0
    const char *nl = memchr(src, '\n', len);
612
0
    if (!nl)
613
0
      break;
614
0
    if (nl > src && nl[-1] == '\r') {
615
0
      strbuf_add(buf, src, nl + 1 - src);
616
0
    } else {
617
0
      strbuf_add(buf, src, nl - src);
618
0
      strbuf_addstr(buf, "\r\n");
619
0
    }
620
0
    len -= nl + 1 - src;
621
0
    src  = nl + 1;
622
0
  }
623
0
  strbuf_add(buf, src, len);
624
625
0
  free(to_free);
626
0
  return 1;
627
0
}
628
629
struct filter_params {
630
  const char *src;
631
  size_t size;
632
  int fd;
633
  const char *cmd;
634
  const char *path;
635
};
636
637
static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
638
0
{
639
  /*
640
   * Spawn cmd and feed the buffer contents through its stdin.
641
   */
642
0
  struct child_process child_process = CHILD_PROCESS_INIT;
643
0
  struct filter_params *params = (struct filter_params *)data;
644
0
  const char *format = params->cmd;
645
0
  int write_err, status;
646
647
  /* apply % substitution to cmd */
648
0
  struct strbuf cmd = STRBUF_INIT;
649
650
  /* expand all %f with the quoted path; quote to preserve space, etc. */
651
0
  while (strbuf_expand_step(&cmd, &format)) {
652
0
    if (skip_prefix(format, "%", &format))
653
0
      strbuf_addch(&cmd, '%');
654
0
    else if (skip_prefix(format, "f", &format))
655
0
      sq_quote_buf(&cmd, params->path);
656
0
    else
657
0
      strbuf_addch(&cmd, '%');
658
0
  }
659
660
0
  strvec_push(&child_process.args, cmd.buf);
661
0
  child_process.use_shell = 1;
662
0
  child_process.in = -1;
663
0
  child_process.out = out;
664
665
0
  if (start_command(&child_process)) {
666
0
    strbuf_release(&cmd);
667
0
    return error(_("cannot fork to run external filter '%s'"),
668
0
           params->cmd);
669
0
  }
670
671
0
  sigchain_push(SIGPIPE, SIG_IGN);
672
673
0
  if (params->src) {
674
0
    write_err = (write_in_full(child_process.in,
675
0
             params->src, params->size) < 0);
676
0
    if (errno == EPIPE)
677
0
      write_err = 0;
678
0
  } else {
679
0
    write_err = copy_fd(params->fd, child_process.in);
680
0
    if (write_err == COPY_WRITE_ERROR && errno == EPIPE)
681
0
      write_err = 0;
682
0
  }
683
684
0
  if (close(child_process.in))
685
0
    write_err = 1;
686
0
  if (write_err)
687
0
    error(_("cannot feed the input to external filter '%s'"),
688
0
          params->cmd);
689
690
0
  sigchain_pop(SIGPIPE);
691
692
0
  status = finish_command(&child_process);
693
0
  if (status)
694
0
    error(_("external filter '%s' failed %d"), params->cmd, status);
695
696
0
  strbuf_release(&cmd);
697
0
  return (write_err || status);
698
0
}
699
700
static int apply_single_file_filter(const char *path, const char *src, size_t len, int fd,
701
            struct strbuf *dst, const char *cmd)
702
0
{
703
  /*
704
   * Create a pipeline to have the command filter the buffer's
705
   * contents.
706
   *
707
   * (child --> cmd) --> us
708
   */
709
0
  int err = 0;
710
0
  struct strbuf nbuf = STRBUF_INIT;
711
0
  struct async async;
712
0
  struct filter_params params;
713
714
0
  memset(&async, 0, sizeof(async));
715
0
  async.proc = filter_buffer_or_fd;
716
0
  async.data = &params;
717
0
  async.out = -1;
718
0
  params.src = src;
719
0
  params.size = len;
720
0
  params.fd = fd;
721
0
  params.cmd = cmd;
722
0
  params.path = path;
723
724
0
  fflush(NULL);
725
0
  if (start_async(&async))
726
0
    return 0; /* error was already reported */
727
728
0
  if (strbuf_read(&nbuf, async.out, 0) < 0) {
729
0
    err = error(_("read from external filter '%s' failed"), cmd);
730
0
  }
731
0
  if (close(async.out)) {
732
0
    err = error(_("read from external filter '%s' failed"), cmd);
733
0
  }
734
0
  if (finish_async(&async)) {
735
0
    err = error(_("external filter '%s' failed"), cmd);
736
0
  }
737
738
0
  if (!err) {
739
0
    strbuf_swap(dst, &nbuf);
740
0
  }
741
0
  strbuf_release(&nbuf);
742
0
  return !err;
743
0
}
744
745
0
#define CAP_CLEAN    (1u<<0)
746
0
#define CAP_SMUDGE   (1u<<1)
747
0
#define CAP_DELAY    (1u<<2)
748
749
struct cmd2process {
750
  struct subprocess_entry subprocess; /* must be the first member! */
751
  unsigned int supported_capabilities;
752
};
753
754
static int subprocess_map_initialized;
755
static struct hashmap subprocess_map;
756
757
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
758
0
{
759
0
  static int versions[] = {2, 0};
760
0
  static struct subprocess_capability capabilities[] = {
761
0
    { "clean",  CAP_CLEAN  },
762
0
    { "smudge", CAP_SMUDGE },
763
0
    { "delay",  CAP_DELAY  },
764
0
    { NULL, 0 }
765
0
  };
766
0
  struct cmd2process *entry = (struct cmd2process *)subprocess;
767
0
  return subprocess_handshake(subprocess, "git-filter", versions, NULL,
768
0
            capabilities,
769
0
            &entry->supported_capabilities);
770
0
}
771
772
static void handle_filter_error(const struct strbuf *filter_status,
773
        struct cmd2process *entry,
774
        const unsigned int wanted_capability)
775
0
{
776
0
  if (!strcmp(filter_status->buf, "error"))
777
0
    ; /* The filter signaled a problem with the file. */
778
0
  else if (!strcmp(filter_status->buf, "abort") && wanted_capability) {
779
    /*
780
     * The filter signaled a permanent problem. Don't try to filter
781
     * files with the same command for the lifetime of the current
782
     * Git process.
783
     */
784
0
     entry->supported_capabilities &= ~wanted_capability;
785
0
  } else {
786
    /*
787
     * Something went wrong with the protocol filter.
788
     * Force shutdown and restart if another blob requires filtering.
789
     */
790
0
    error(_("external filter '%s' failed"), entry->subprocess.cmd);
791
0
    subprocess_stop(&subprocess_map, &entry->subprocess);
792
0
    free(entry);
793
0
  }
794
0
}
795
796
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
797
           int fd, struct strbuf *dst, const char *cmd,
798
           const unsigned int wanted_capability,
799
           const struct checkout_metadata *meta,
800
           struct delayed_checkout *dco)
801
0
{
802
0
  int err;
803
0
  int can_delay = 0;
804
0
  struct cmd2process *entry;
805
0
  struct child_process *process;
806
0
  struct strbuf nbuf = STRBUF_INIT;
807
0
  struct strbuf filter_status = STRBUF_INIT;
808
0
  const char *filter_type;
809
810
0
  if (!subprocess_map_initialized) {
811
0
    subprocess_map_initialized = 1;
812
0
    hashmap_init(&subprocess_map, cmd2process_cmp, NULL, 0);
813
0
    entry = NULL;
814
0
  } else {
815
0
    entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
816
0
  }
817
818
0
  fflush(NULL);
819
820
0
  if (!entry) {
821
0
    entry = xmalloc(sizeof(*entry));
822
0
    entry->supported_capabilities = 0;
823
824
0
    if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) {
825
0
      free(entry);
826
0
      return 0;
827
0
    }
828
0
  }
829
0
  process = &entry->subprocess.process;
830
831
0
  if (!(entry->supported_capabilities & wanted_capability))
832
0
    return 0;
833
834
0
  if (wanted_capability & CAP_CLEAN)
835
0
    filter_type = "clean";
836
0
  else if (wanted_capability & CAP_SMUDGE)
837
0
    filter_type = "smudge";
838
0
  else
839
0
    die(_("unexpected filter type"));
840
841
0
  sigchain_push(SIGPIPE, SIG_IGN);
842
843
0
  assert(strlen(filter_type) < LARGE_PACKET_DATA_MAX - strlen("command=\n"));
844
0
  err = packet_write_fmt_gently(process->in, "command=%s\n", filter_type);
845
0
  if (err)
846
0
    goto done;
847
848
0
  err = strlen(path) > LARGE_PACKET_DATA_MAX - strlen("pathname=\n");
849
0
  if (err) {
850
0
    error(_("path name too long for external filter"));
851
0
    goto done;
852
0
  }
853
854
0
  err = packet_write_fmt_gently(process->in, "pathname=%s\n", path);
855
0
  if (err)
856
0
    goto done;
857
858
0
  if (meta && meta->refname) {
859
0
    err = packet_write_fmt_gently(process->in, "ref=%s\n", meta->refname);
860
0
    if (err)
861
0
      goto done;
862
0
  }
863
864
0
  if (meta && !is_null_oid(&meta->treeish)) {
865
0
    err = packet_write_fmt_gently(process->in, "treeish=%s\n", oid_to_hex(&meta->treeish));
866
0
    if (err)
867
0
      goto done;
868
0
  }
869
870
0
  if (meta && !is_null_oid(&meta->blob)) {
871
0
    err = packet_write_fmt_gently(process->in, "blob=%s\n", oid_to_hex(&meta->blob));
872
0
    if (err)
873
0
      goto done;
874
0
  }
875
876
0
  if ((entry->supported_capabilities & CAP_DELAY) &&
877
0
      dco && dco->state == CE_CAN_DELAY) {
878
0
    can_delay = 1;
879
0
    err = packet_write_fmt_gently(process->in, "can-delay=1\n");
880
0
    if (err)
881
0
      goto done;
882
0
  }
883
884
0
  err = packet_flush_gently(process->in);
885
0
  if (err)
886
0
    goto done;
887
888
0
  if (fd >= 0)
889
0
    err = write_packetized_from_fd_no_flush(fd, process->in);
890
0
  else
891
0
    err = write_packetized_from_buf_no_flush(src, len, process->in);
892
0
  if (err)
893
0
    goto done;
894
895
0
  err = packet_flush_gently(process->in);
896
0
  if (err)
897
0
    goto done;
898
899
0
  err = subprocess_read_status(process->out, &filter_status);
900
0
  if (err)
901
0
    goto done;
902
903
0
  if (can_delay && !strcmp(filter_status.buf, "delayed")) {
904
0
    string_list_insert(&dco->filters, cmd);
905
0
    string_list_insert(&dco->paths, path);
906
0
  } else {
907
    /* The filter got the blob and wants to send us a response. */
908
0
    err = strcmp(filter_status.buf, "success");
909
0
    if (err)
910
0
      goto done;
911
912
0
    err = read_packetized_to_strbuf(process->out, &nbuf,
913
0
            PACKET_READ_GENTLE_ON_EOF) < 0;
914
0
    if (err)
915
0
      goto done;
916
917
0
    err = subprocess_read_status(process->out, &filter_status);
918
0
    if (err)
919
0
      goto done;
920
921
0
    err = strcmp(filter_status.buf, "success");
922
0
  }
923
924
0
done:
925
0
  sigchain_pop(SIGPIPE);
926
927
0
  if (err)
928
0
    handle_filter_error(&filter_status, entry, wanted_capability);
929
0
  else
930
0
    strbuf_swap(dst, &nbuf);
931
0
  strbuf_release(&nbuf);
932
0
  strbuf_release(&filter_status);
933
0
  return !err;
934
0
}
935
936
937
int async_query_available_blobs(const char *cmd, struct string_list *available_paths)
938
0
{
939
0
  int err;
940
0
  char *line;
941
0
  struct cmd2process *entry;
942
0
  struct child_process *process;
943
0
  struct strbuf filter_status = STRBUF_INIT;
944
945
0
  assert(subprocess_map_initialized);
946
0
  entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
947
0
  if (!entry) {
948
0
    error(_("external filter '%s' is not available anymore although "
949
0
      "not all paths have been filtered"), cmd);
950
0
    return 0;
951
0
  }
952
0
  process = &entry->subprocess.process;
953
0
  sigchain_push(SIGPIPE, SIG_IGN);
954
955
0
  err = packet_write_fmt_gently(
956
0
    process->in, "command=list_available_blobs\n");
957
0
  if (err)
958
0
    goto done;
959
960
0
  err = packet_flush_gently(process->in);
961
0
  if (err)
962
0
    goto done;
963
964
0
  while ((line = packet_read_line(process->out, NULL))) {
965
0
    const char *path;
966
0
    if (skip_prefix(line, "pathname=", &path))
967
0
      string_list_insert(available_paths, path);
968
0
    else
969
0
      ; /* ignore unknown keys */
970
0
  }
971
972
0
  err = subprocess_read_status(process->out, &filter_status);
973
0
  if (err)
974
0
    goto done;
975
976
0
  err = strcmp(filter_status.buf, "success");
977
978
0
done:
979
0
  sigchain_pop(SIGPIPE);
980
981
0
  if (err)
982
0
    handle_filter_error(&filter_status, entry, 0);
983
0
  strbuf_release(&filter_status);
984
0
  return !err;
985
0
}
986
987
static struct convert_driver {
988
  const char *name;
989
  struct convert_driver *next;
990
  char *smudge;
991
  char *clean;
992
  char *process;
993
  int required;
994
} *user_convert, **user_convert_tail;
995
996
static int apply_filter(const char *path, const char *src, size_t len,
997
      int fd, struct strbuf *dst, struct convert_driver *drv,
998
      const unsigned int wanted_capability,
999
      const struct checkout_metadata *meta,
1000
      struct delayed_checkout *dco)
1001
0
{
1002
0
  const char *cmd = NULL;
1003
1004
0
  if (!drv)
1005
0
    return 0;
1006
1007
0
  if (!dst)
1008
0
    return 1;
1009
1010
0
  if ((wanted_capability & CAP_CLEAN) && !drv->process && drv->clean)
1011
0
    cmd = drv->clean;
1012
0
  else if ((wanted_capability & CAP_SMUDGE) && !drv->process && drv->smudge)
1013
0
    cmd = drv->smudge;
1014
1015
0
  if (cmd && *cmd)
1016
0
    return apply_single_file_filter(path, src, len, fd, dst, cmd);
1017
0
  else if (drv->process && *drv->process)
1018
0
    return apply_multi_file_filter(path, src, len, fd, dst,
1019
0
      drv->process, wanted_capability, meta, dco);
1020
1021
0
  return 0;
1022
0
}
1023
1024
static int read_convert_config(const char *var, const char *value,
1025
             const struct config_context *ctx UNUSED,
1026
             void *cb UNUSED)
1027
0
{
1028
0
  const char *key, *name;
1029
0
  size_t namelen;
1030
0
  struct convert_driver *drv;
1031
1032
  /*
1033
   * External conversion drivers are configured using
1034
   * "filter.<name>.variable".
1035
   */
1036
0
  if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
1037
0
    return 0;
1038
0
  for (drv = user_convert; drv; drv = drv->next)
1039
0
    if (!xstrncmpz(drv->name, name, namelen))
1040
0
      break;
1041
0
  if (!drv) {
1042
0
    CALLOC_ARRAY(drv, 1);
1043
0
    drv->name = xmemdupz(name, namelen);
1044
0
    *user_convert_tail = drv;
1045
0
    user_convert_tail = &(drv->next);
1046
0
  }
1047
1048
  /*
1049
   * filter.<name>.smudge and filter.<name>.clean specifies
1050
   * the command line:
1051
   *
1052
   *  command-line
1053
   *
1054
   * The command-line will not be interpolated in any way.
1055
   */
1056
1057
0
  if (!strcmp("smudge", key)) {
1058
0
    FREE_AND_NULL(drv->smudge);
1059
0
    return git_config_string(&drv->smudge, var, value);
1060
0
  }
1061
1062
0
  if (!strcmp("clean", key)) {
1063
0
    FREE_AND_NULL(drv->clean);
1064
0
    return git_config_string(&drv->clean, var, value);
1065
0
  }
1066
1067
0
  if (!strcmp("process", key)) {
1068
0
    FREE_AND_NULL(drv->process);
1069
0
    return git_config_string(&drv->process, var, value);
1070
0
  }
1071
1072
0
  if (!strcmp("required", key)) {
1073
0
    drv->required = git_config_bool(var, value);
1074
0
    return 0;
1075
0
  }
1076
1077
0
  return 0;
1078
0
}
1079
1080
static int count_ident(const char *cp, unsigned long size)
1081
0
{
1082
  /*
1083
   * "$Id: 0000000000000000000000000000000000000000 $" <=> "$Id$"
1084
   */
1085
0
  int cnt = 0;
1086
0
  char ch;
1087
1088
0
  while (size) {
1089
0
    ch = *cp++;
1090
0
    size--;
1091
0
    if (ch != '$')
1092
0
      continue;
1093
0
    if (size < 3)
1094
0
      break;
1095
0
    if (memcmp("Id", cp, 2))
1096
0
      continue;
1097
0
    ch = cp[2];
1098
0
    cp += 3;
1099
0
    size -= 3;
1100
0
    if (ch == '$')
1101
0
      cnt++; /* $Id$ */
1102
0
    if (ch != ':')
1103
0
      continue;
1104
1105
    /*
1106
     * "$Id: ... "; scan up to the closing dollar sign and discard.
1107
     */
1108
0
    while (size) {
1109
0
      ch = *cp++;
1110
0
      size--;
1111
0
      if (ch == '$') {
1112
0
        cnt++;
1113
0
        break;
1114
0
      }
1115
0
      if (ch == '\n')
1116
0
        break;
1117
0
    }
1118
0
  }
1119
0
  return cnt;
1120
0
}
1121
1122
static int ident_to_git(const char *src, size_t len,
1123
      struct strbuf *buf, int ident)
1124
0
{
1125
0
  char *dst, *dollar;
1126
1127
0
  if (!ident || (src && !count_ident(src, len)))
1128
0
    return 0;
1129
1130
0
  if (!buf)
1131
0
    return 1;
1132
1133
  /* only grow if not in place */
1134
0
  if (strbuf_avail(buf) + buf->len < len)
1135
0
    strbuf_grow(buf, len - buf->len);
1136
0
  dst = buf->buf;
1137
0
  for (;;) {
1138
0
    dollar = memchr(src, '$', len);
1139
0
    if (!dollar)
1140
0
      break;
1141
0
    memmove(dst, src, dollar + 1 - src);
1142
0
    dst += dollar + 1 - src;
1143
0
    len -= dollar + 1 - src;
1144
0
    src  = dollar + 1;
1145
1146
0
    if (len > 3 && !memcmp(src, "Id:", 3)) {
1147
0
      dollar = memchr(src + 3, '$', len - 3);
1148
0
      if (!dollar)
1149
0
        break;
1150
0
      if (memchr(src + 3, '\n', dollar - src - 3)) {
1151
        /* Line break before the next dollar. */
1152
0
        continue;
1153
0
      }
1154
1155
0
      memcpy(dst, "Id$", 3);
1156
0
      dst += 3;
1157
0
      len -= dollar + 1 - src;
1158
0
      src  = dollar + 1;
1159
0
    }
1160
0
  }
1161
0
  memmove(dst, src, len);
1162
0
  strbuf_setlen(buf, dst + len - buf->buf);
1163
0
  return 1;
1164
0
}
1165
1166
static int ident_to_worktree(const char *src, size_t len,
1167
           struct strbuf *buf, int ident)
1168
0
{
1169
0
  struct object_id oid;
1170
0
  char *to_free = NULL, *dollar, *spc;
1171
0
  int cnt;
1172
1173
0
  if (!ident)
1174
0
    return 0;
1175
1176
0
  cnt = count_ident(src, len);
1177
0
  if (!cnt)
1178
0
    return 0;
1179
1180
  /* are we "faking" in place editing ? */
1181
0
  if (src == buf->buf)
1182
0
    to_free = strbuf_detach(buf, NULL);
1183
0
  hash_object_file(the_hash_algo, src, len, OBJ_BLOB, &oid);
1184
1185
0
  strbuf_grow(buf, len + cnt * (the_hash_algo->hexsz + 3));
1186
0
  for (;;) {
1187
    /* step 1: run to the next '$' */
1188
0
    dollar = memchr(src, '$', len);
1189
0
    if (!dollar)
1190
0
      break;
1191
0
    strbuf_add(buf, src, dollar + 1 - src);
1192
0
    len -= dollar + 1 - src;
1193
0
    src  = dollar + 1;
1194
1195
    /* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
1196
0
    if (len < 3 || memcmp("Id", src, 2))
1197
0
      continue;
1198
1199
    /* step 3: skip over Id$ or Id:xxxxx$ */
1200
0
    if (src[2] == '$') {
1201
0
      src += 3;
1202
0
      len -= 3;
1203
0
    } else if (src[2] == ':') {
1204
      /*
1205
       * It's possible that an expanded Id has crept its way into the
1206
       * repository, we cope with that by stripping the expansion out.
1207
       * This is probably not a good idea, since it will cause changes
1208
       * on checkout, which won't go away by stash, but let's keep it
1209
       * for git-style ids.
1210
       */
1211
0
      dollar = memchr(src + 3, '$', len - 3);
1212
0
      if (!dollar) {
1213
        /* incomplete keyword, no more '$', so just quit the loop */
1214
0
        break;
1215
0
      }
1216
1217
0
      if (memchr(src + 3, '\n', dollar - src - 3)) {
1218
        /* Line break before the next dollar. */
1219
0
        continue;
1220
0
      }
1221
1222
0
      spc = memchr(src + 4, ' ', dollar - src - 4);
1223
0
      if (spc && spc < dollar-1) {
1224
        /* There are spaces in unexpected places.
1225
         * This is probably an id from some other
1226
         * versioning system. Keep it for now.
1227
         */
1228
0
        continue;
1229
0
      }
1230
1231
0
      len -= dollar + 1 - src;
1232
0
      src  = dollar + 1;
1233
0
    } else {
1234
      /* it wasn't a "Id$" or "Id:xxxx$" */
1235
0
      continue;
1236
0
    }
1237
1238
    /* step 4: substitute */
1239
0
    strbuf_addstr(buf, "Id: ");
1240
0
    strbuf_addstr(buf, oid_to_hex(&oid));
1241
0
    strbuf_addstr(buf, " $");
1242
0
  }
1243
0
  strbuf_add(buf, src, len);
1244
1245
0
  free(to_free);
1246
0
  return 1;
1247
0
}
1248
1249
static const char *git_path_check_encoding(struct attr_check_item *check)
1250
0
{
1251
0
  const char *value = check->value;
1252
1253
0
  if (ATTR_UNSET(value) || !strlen(value))
1254
0
    return NULL;
1255
1256
0
  if (ATTR_TRUE(value) || ATTR_FALSE(value)) {
1257
0
    die(_("true/false are no valid working-tree-encodings"));
1258
0
  }
1259
1260
  /* Don't encode to the default encoding */
1261
0
  if (same_encoding(value, default_encoding))
1262
0
    return NULL;
1263
1264
0
  return value;
1265
0
}
1266
1267
static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check)
1268
0
{
1269
0
  const char *value = check->value;
1270
1271
0
  if (ATTR_TRUE(value))
1272
0
    return CRLF_TEXT;
1273
0
  else if (ATTR_FALSE(value))
1274
0
    return CRLF_BINARY;
1275
0
  else if (ATTR_UNSET(value))
1276
0
    ;
1277
0
  else if (!strcmp(value, "input"))
1278
0
    return CRLF_TEXT_INPUT;
1279
0
  else if (!strcmp(value, "auto"))
1280
0
    return CRLF_AUTO;
1281
0
  return CRLF_UNDEFINED;
1282
0
}
1283
1284
static enum eol git_path_check_eol(struct attr_check_item *check)
1285
0
{
1286
0
  const char *value = check->value;
1287
1288
0
  if (ATTR_UNSET(value))
1289
0
    ;
1290
0
  else if (!strcmp(value, "lf"))
1291
0
    return EOL_LF;
1292
0
  else if (!strcmp(value, "crlf"))
1293
0
    return EOL_CRLF;
1294
0
  return EOL_UNSET;
1295
0
}
1296
1297
static struct convert_driver *git_path_check_convert(struct attr_check_item *check)
1298
0
{
1299
0
  const char *value = check->value;
1300
0
  struct convert_driver *drv;
1301
1302
0
  if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
1303
0
    return NULL;
1304
0
  for (drv = user_convert; drv; drv = drv->next)
1305
0
    if (!strcmp(value, drv->name))
1306
0
      return drv;
1307
0
  return NULL;
1308
0
}
1309
1310
static int git_path_check_ident(struct attr_check_item *check)
1311
0
{
1312
0
  const char *value = check->value;
1313
1314
0
  return !!ATTR_TRUE(value);
1315
0
}
1316
1317
static struct attr_check *check;
1318
1319
void convert_attrs(struct index_state *istate,
1320
       struct conv_attrs *ca, const char *path)
1321
0
{
1322
0
  struct attr_check_item *ccheck = NULL;
1323
1324
0
  if (!check) {
1325
0
    check = attr_check_initl("crlf", "ident", "filter",
1326
0
           "eol", "text", "working-tree-encoding",
1327
0
           NULL);
1328
0
    user_convert_tail = &user_convert;
1329
0
    repo_config(the_repository, read_convert_config, NULL);
1330
0
  }
1331
1332
0
  git_check_attr(istate, path, check);
1333
0
  ccheck = check->items;
1334
0
  ca->crlf_action = git_path_check_crlf(ccheck + 4);
1335
0
  if (ca->crlf_action == CRLF_UNDEFINED)
1336
0
    ca->crlf_action = git_path_check_crlf(ccheck + 0);
1337
0
  ca->ident = git_path_check_ident(ccheck + 1);
1338
0
  ca->drv = git_path_check_convert(ccheck + 2);
1339
0
  if (ca->crlf_action != CRLF_BINARY) {
1340
0
    enum eol eol_attr = git_path_check_eol(ccheck + 3);
1341
0
    if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
1342
0
      ca->crlf_action = CRLF_AUTO_INPUT;
1343
0
    else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
1344
0
      ca->crlf_action = CRLF_AUTO_CRLF;
1345
0
    else if (eol_attr == EOL_LF)
1346
0
      ca->crlf_action = CRLF_TEXT_INPUT;
1347
0
    else if (eol_attr == EOL_CRLF)
1348
0
      ca->crlf_action = CRLF_TEXT_CRLF;
1349
0
  }
1350
0
  ca->working_tree_encoding = git_path_check_encoding(ccheck + 5);
1351
1352
  /* Save attr and make a decision for action */
1353
0
  ca->attr_action = ca->crlf_action;
1354
0
  if (ca->crlf_action == CRLF_TEXT)
1355
0
    ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT;
1356
0
  if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE)
1357
0
    ca->crlf_action = CRLF_BINARY;
1358
0
  if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_TRUE)
1359
0
    ca->crlf_action = CRLF_AUTO_CRLF;
1360
0
  if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_INPUT)
1361
0
    ca->crlf_action = CRLF_AUTO_INPUT;
1362
0
}
1363
1364
void reset_parsed_attributes(void)
1365
0
{
1366
0
  struct convert_driver *drv, *next;
1367
1368
0
  attr_check_free(check);
1369
0
  check = NULL;
1370
0
  reset_merge_attributes();
1371
1372
0
  for (drv = user_convert; drv; drv = next) {
1373
0
    next = drv->next;
1374
0
    free((void *)drv->name);
1375
0
    free((void *)drv->smudge);
1376
0
    free((void *)drv->clean);
1377
0
    free((void *)drv->process);
1378
0
    free(drv);
1379
0
  }
1380
0
  user_convert = NULL;
1381
0
  user_convert_tail = NULL;
1382
0
}
1383
1384
int would_convert_to_git_filter_fd(struct index_state *istate, const char *path)
1385
0
{
1386
0
  struct conv_attrs ca;
1387
1388
0
  convert_attrs(istate, &ca, path);
1389
0
  if (!ca.drv)
1390
0
    return 0;
1391
1392
  /*
1393
   * Apply a filter to an fd only if the filter is required to succeed.
1394
   * We must die if the filter fails, because the original data before
1395
   * filtering is not available.
1396
   */
1397
0
  if (!ca.drv->required)
1398
0
    return 0;
1399
1400
0
  return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL, NULL);
1401
0
}
1402
1403
const char *get_convert_attr_ascii(struct index_state *istate, const char *path)
1404
0
{
1405
0
  struct conv_attrs ca;
1406
1407
0
  convert_attrs(istate, &ca, path);
1408
0
  switch (ca.attr_action) {
1409
0
  case CRLF_UNDEFINED:
1410
0
    return "";
1411
0
  case CRLF_BINARY:
1412
0
    return "-text";
1413
0
  case CRLF_TEXT:
1414
0
    return "text";
1415
0
  case CRLF_TEXT_INPUT:
1416
0
    return "text eol=lf";
1417
0
  case CRLF_TEXT_CRLF:
1418
0
    return "text eol=crlf";
1419
0
  case CRLF_AUTO:
1420
0
    return "text=auto";
1421
0
  case CRLF_AUTO_CRLF:
1422
0
    return "text=auto eol=crlf";
1423
0
  case CRLF_AUTO_INPUT:
1424
0
    return "text=auto eol=lf";
1425
0
  }
1426
0
  return "";
1427
0
}
1428
1429
int convert_to_git(struct index_state *istate,
1430
       const char *path, const char *src, size_t len,
1431
       struct strbuf *dst, int conv_flags)
1432
0
{
1433
0
  int ret = 0;
1434
0
  struct conv_attrs ca;
1435
1436
0
  convert_attrs(istate, &ca, path);
1437
1438
0
  ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL, NULL);
1439
0
  if (!ret && ca.drv && ca.drv->required)
1440
0
    die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
1441
1442
0
  if (ret && dst) {
1443
0
    src = dst->buf;
1444
0
    len = dst->len;
1445
0
  }
1446
1447
0
  ret |= encode_to_git(path, src, len, dst, ca.working_tree_encoding, conv_flags);
1448
0
  if (ret && dst) {
1449
0
    src = dst->buf;
1450
0
    len = dst->len;
1451
0
  }
1452
1453
0
  if (!(conv_flags & CONV_EOL_KEEP_CRLF)) {
1454
0
    ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags);
1455
0
    if (ret && dst) {
1456
0
      src = dst->buf;
1457
0
      len = dst->len;
1458
0
    }
1459
0
  }
1460
0
  return ret | ident_to_git(src, len, dst, ca.ident);
1461
0
}
1462
1463
void convert_to_git_filter_fd(struct index_state *istate,
1464
            const char *path, int fd, struct strbuf *dst,
1465
            int conv_flags)
1466
0
{
1467
0
  struct conv_attrs ca;
1468
0
  convert_attrs(istate, &ca, path);
1469
1470
0
  assert(ca.drv);
1471
1472
0
  if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL))
1473
0
    die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
1474
1475
0
  encode_to_git(path, dst->buf, dst->len, dst, ca.working_tree_encoding, conv_flags);
1476
0
  crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
1477
0
  ident_to_git(dst->buf, dst->len, dst, ca.ident);
1478
0
}
1479
1480
static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
1481
                 const char *path, const char *src,
1482
                 size_t len, struct strbuf *dst,
1483
                 int normalizing,
1484
                 const struct checkout_metadata *meta,
1485
                 struct delayed_checkout *dco)
1486
0
{
1487
0
  int ret = 0, ret_filter = 0;
1488
1489
0
  ret |= ident_to_worktree(src, len, dst, ca->ident);
1490
0
  if (ret) {
1491
0
    src = dst->buf;
1492
0
    len = dst->len;
1493
0
  }
1494
  /*
1495
   * CRLF conversion can be skipped if normalizing, unless there
1496
   * is a smudge or process filter (even if the process filter doesn't
1497
   * support smudge).  The filters might expect CRLFs.
1498
   */
1499
0
  if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) {
1500
0
    ret |= crlf_to_worktree(src, len, dst, ca->crlf_action);
1501
0
    if (ret) {
1502
0
      src = dst->buf;
1503
0
      len = dst->len;
1504
0
    }
1505
0
  }
1506
1507
0
  ret |= encode_to_worktree(path, src, len, dst, ca->working_tree_encoding);
1508
0
  if (ret) {
1509
0
    src = dst->buf;
1510
0
    len = dst->len;
1511
0
  }
1512
1513
0
  ret_filter = apply_filter(
1514
0
    path, src, len, -1, dst, ca->drv, CAP_SMUDGE, meta, dco);
1515
0
  if (!ret_filter && ca->drv && ca->drv->required)
1516
0
    die(_("%s: smudge filter %s failed"), path, ca->drv->name);
1517
1518
0
  return ret | ret_filter;
1519
0
}
1520
1521
int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
1522
             const char *path, const char *src,
1523
             size_t len, struct strbuf *dst,
1524
             const struct checkout_metadata *meta,
1525
             void *dco)
1526
0
{
1527
0
  return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
1528
0
               meta, dco);
1529
0
}
1530
1531
int convert_to_working_tree_ca(const struct conv_attrs *ca,
1532
             const char *path, const char *src,
1533
             size_t len, struct strbuf *dst,
1534
             const struct checkout_metadata *meta)
1535
0
{
1536
0
  return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
1537
0
               meta, NULL);
1538
0
}
1539
1540
int renormalize_buffer(struct index_state *istate, const char *path,
1541
           const char *src, size_t len, struct strbuf *dst)
1542
0
{
1543
0
  struct conv_attrs ca;
1544
0
  int ret;
1545
1546
0
  convert_attrs(istate, &ca, path);
1547
0
  ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1,
1548
0
              NULL, NULL);
1549
0
  if (ret) {
1550
0
    src = dst->buf;
1551
0
    len = dst->len;
1552
0
  }
1553
0
  return ret | convert_to_git(istate, path, src, len, dst, CONV_EOL_RENORMALIZE);
1554
0
}
1555
1556
/*****************************************************************
1557
 *
1558
 * Streaming conversion support
1559
 *
1560
 *****************************************************************/
1561
1562
typedef int (*filter_fn)(struct stream_filter *,
1563
       const char *input, size_t *isize_p,
1564
       char *output, size_t *osize_p);
1565
typedef void (*free_fn)(struct stream_filter *);
1566
1567
struct stream_filter_vtbl {
1568
  filter_fn filter;
1569
  free_fn free;
1570
};
1571
1572
struct stream_filter {
1573
  struct stream_filter_vtbl *vtbl;
1574
};
1575
1576
static int null_filter_fn(struct stream_filter *filter UNUSED,
1577
        const char *input, size_t *isize_p,
1578
        char *output, size_t *osize_p)
1579
0
{
1580
0
  size_t count;
1581
1582
0
  if (!input)
1583
0
    return 0; /* we do not keep any states */
1584
0
  count = *isize_p;
1585
0
  if (*osize_p < count)
1586
0
    count = *osize_p;
1587
0
  if (count) {
1588
0
    memmove(output, input, count);
1589
0
    *isize_p -= count;
1590
0
    *osize_p -= count;
1591
0
  }
1592
0
  return 0;
1593
0
}
1594
1595
static void null_free_fn(struct stream_filter *filter UNUSED)
1596
0
{
1597
0
  ; /* nothing -- null instances are shared */
1598
0
}
1599
1600
static struct stream_filter_vtbl null_vtbl = {
1601
  .filter = null_filter_fn,
1602
  .free = null_free_fn,
1603
};
1604
1605
static struct stream_filter null_filter_singleton = {
1606
  .vtbl = &null_vtbl,
1607
};
1608
1609
int is_null_stream_filter(struct stream_filter *filter)
1610
0
{
1611
0
  return filter == &null_filter_singleton;
1612
0
}
1613
1614
1615
/*
1616
 * LF-to-CRLF filter
1617
 */
1618
1619
struct lf_to_crlf_filter {
1620
  struct stream_filter filter;
1621
  unsigned has_held:1;
1622
  char held;
1623
};
1624
1625
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
1626
        const char *input, size_t *isize_p,
1627
        char *output, size_t *osize_p)
1628
0
{
1629
0
  size_t count, o = 0;
1630
0
  struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
1631
1632
  /*
1633
   * We may be holding onto the CR to see if it is followed by a
1634
   * LF, in which case we would need to go to the main loop.
1635
   * Otherwise, just emit it to the output stream.
1636
   */
1637
0
  if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) {
1638
0
    output[o++] = lf_to_crlf->held;
1639
0
    lf_to_crlf->has_held = 0;
1640
0
  }
1641
1642
  /* We are told to drain */
1643
0
  if (!input) {
1644
0
    *osize_p -= o;
1645
0
    return 0;
1646
0
  }
1647
1648
0
  count = *isize_p;
1649
0
  if (count || lf_to_crlf->has_held) {
1650
0
    size_t i;
1651
0
    int was_cr = 0;
1652
1653
0
    if (lf_to_crlf->has_held) {
1654
0
      was_cr = 1;
1655
0
      lf_to_crlf->has_held = 0;
1656
0
    }
1657
1658
0
    for (i = 0; o < *osize_p && i < count; i++) {
1659
0
      char ch = input[i];
1660
1661
0
      if (ch == '\n') {
1662
0
        output[o++] = '\r';
1663
0
      } else if (was_cr) {
1664
        /*
1665
         * Previous round saw CR and it is not followed
1666
         * by a LF; emit the CR before processing the
1667
         * current character.
1668
         */
1669
0
        output[o++] = '\r';
1670
0
      }
1671
1672
      /*
1673
       * We may have consumed the last output slot,
1674
       * in which case we need to break out of this
1675
       * loop; hold the current character before
1676
       * returning.
1677
       */
1678
0
      if (*osize_p <= o) {
1679
0
        lf_to_crlf->has_held = 1;
1680
0
        lf_to_crlf->held = ch;
1681
0
        continue; /* break but increment i */
1682
0
      }
1683
1684
0
      if (ch == '\r') {
1685
0
        was_cr = 1;
1686
0
        continue;
1687
0
      }
1688
1689
0
      was_cr = 0;
1690
0
      output[o++] = ch;
1691
0
    }
1692
1693
0
    *osize_p -= o;
1694
0
    *isize_p -= i;
1695
1696
0
    if (!lf_to_crlf->has_held && was_cr) {
1697
0
      lf_to_crlf->has_held = 1;
1698
0
      lf_to_crlf->held = '\r';
1699
0
    }
1700
0
  }
1701
0
  return 0;
1702
0
}
1703
1704
static void lf_to_crlf_free_fn(struct stream_filter *filter)
1705
0
{
1706
0
  free(filter);
1707
0
}
1708
1709
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
1710
  .filter = lf_to_crlf_filter_fn,
1711
  .free = lf_to_crlf_free_fn,
1712
};
1713
1714
static struct stream_filter *lf_to_crlf_filter(void)
1715
0
{
1716
0
  struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
1717
1718
0
  lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
1719
0
  return (struct stream_filter *)lf_to_crlf;
1720
0
}
1721
1722
/*
1723
 * Cascade filter
1724
 */
1725
#define FILTER_BUFFER 1024
1726
struct cascade_filter {
1727
  struct stream_filter filter;
1728
  struct stream_filter *one;
1729
  struct stream_filter *two;
1730
  char buf[FILTER_BUFFER];
1731
  int end, ptr;
1732
};
1733
1734
static int cascade_filter_fn(struct stream_filter *filter,
1735
           const char *input, size_t *isize_p,
1736
           char *output, size_t *osize_p)
1737
0
{
1738
0
  struct cascade_filter *cas = (struct cascade_filter *) filter;
1739
0
  size_t filled = 0;
1740
0
  size_t sz = *osize_p;
1741
0
  size_t to_feed, remaining;
1742
1743
  /*
1744
   * input -- (one) --> buf -- (two) --> output
1745
   */
1746
0
  while (filled < sz) {
1747
0
    remaining = sz - filled;
1748
1749
    /* do we already have something to feed two with? */
1750
0
    if (cas->ptr < cas->end) {
1751
0
      to_feed = cas->end - cas->ptr;
1752
0
      if (stream_filter(cas->two,
1753
0
            cas->buf + cas->ptr, &to_feed,
1754
0
            output + filled, &remaining))
1755
0
        return -1;
1756
0
      cas->ptr += (cas->end - cas->ptr) - to_feed;
1757
0
      filled = sz - remaining;
1758
0
      continue;
1759
0
    }
1760
1761
    /* feed one from upstream and have it emit into our buffer */
1762
0
    to_feed = input ? *isize_p : 0;
1763
0
    if (input && !to_feed)
1764
0
      break;
1765
0
    remaining = sizeof(cas->buf);
1766
0
    if (stream_filter(cas->one,
1767
0
          input, &to_feed,
1768
0
          cas->buf, &remaining))
1769
0
      return -1;
1770
0
    cas->end = sizeof(cas->buf) - remaining;
1771
0
    cas->ptr = 0;
1772
0
    if (input) {
1773
0
      size_t fed = *isize_p - to_feed;
1774
0
      *isize_p -= fed;
1775
0
      input += fed;
1776
0
    }
1777
1778
    /* do we know that we drained one completely? */
1779
0
    if (input || cas->end)
1780
0
      continue;
1781
1782
    /* tell two to drain; we have nothing more to give it */
1783
0
    to_feed = 0;
1784
0
    remaining = sz - filled;
1785
0
    if (stream_filter(cas->two,
1786
0
          NULL, &to_feed,
1787
0
          output + filled, &remaining))
1788
0
      return -1;
1789
0
    if (remaining == (sz - filled))
1790
0
      break; /* completely drained two */
1791
0
    filled = sz - remaining;
1792
0
  }
1793
0
  *osize_p -= filled;
1794
0
  return 0;
1795
0
}
1796
1797
static void cascade_free_fn(struct stream_filter *filter)
1798
0
{
1799
0
  struct cascade_filter *cas = (struct cascade_filter *)filter;
1800
0
  free_stream_filter(cas->one);
1801
0
  free_stream_filter(cas->two);
1802
0
  free(filter);
1803
0
}
1804
1805
static struct stream_filter_vtbl cascade_vtbl = {
1806
  .filter = cascade_filter_fn,
1807
  .free = cascade_free_fn,
1808
};
1809
1810
static struct stream_filter *cascade_filter(struct stream_filter *one,
1811
              struct stream_filter *two)
1812
0
{
1813
0
  struct cascade_filter *cascade;
1814
1815
0
  if (!one || is_null_stream_filter(one))
1816
0
    return two;
1817
0
  if (!two || is_null_stream_filter(two))
1818
0
    return one;
1819
1820
0
  cascade = xmalloc(sizeof(*cascade));
1821
0
  cascade->one = one;
1822
0
  cascade->two = two;
1823
0
  cascade->end = cascade->ptr = 0;
1824
0
  cascade->filter.vtbl = &cascade_vtbl;
1825
0
  return (struct stream_filter *)cascade;
1826
0
}
1827
1828
/*
1829
 * ident filter
1830
 */
1831
0
#define IDENT_DRAINING (-1)
1832
0
#define IDENT_SKIPPING (-2)
1833
struct ident_filter {
1834
  struct stream_filter filter;
1835
  struct strbuf left;
1836
  int state;
1837
  char ident[GIT_MAX_HEXSZ + 5]; /* ": x40 $" */
1838
};
1839
1840
static int is_foreign_ident(const char *str)
1841
0
{
1842
0
  int i;
1843
1844
0
  if (!skip_prefix(str, "$Id: ", &str))
1845
0
    return 0;
1846
0
  for (i = 0; str[i]; i++) {
1847
0
    if (isspace(str[i]) && str[i+1] != '$')
1848
0
      return 1;
1849
0
  }
1850
0
  return 0;
1851
0
}
1852
1853
static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
1854
0
{
1855
0
  size_t to_drain = ident->left.len;
1856
1857
0
  if (*osize_p < to_drain)
1858
0
    to_drain = *osize_p;
1859
0
  if (to_drain) {
1860
0
    memcpy(*output_p, ident->left.buf, to_drain);
1861
0
    strbuf_remove(&ident->left, 0, to_drain);
1862
0
    *output_p += to_drain;
1863
0
    *osize_p -= to_drain;
1864
0
  }
1865
0
  if (!ident->left.len)
1866
0
    ident->state = 0;
1867
0
}
1868
1869
static int ident_filter_fn(struct stream_filter *filter,
1870
         const char *input, size_t *isize_p,
1871
         char *output, size_t *osize_p)
1872
0
{
1873
0
  struct ident_filter *ident = (struct ident_filter *)filter;
1874
0
  static const char head[] = "$Id";
1875
1876
0
  if (!input) {
1877
    /* drain upon eof */
1878
0
    switch (ident->state) {
1879
0
    default:
1880
0
      strbuf_add(&ident->left, head, ident->state);
1881
      /* fallthrough */
1882
0
    case IDENT_SKIPPING:
1883
      /* fallthrough */
1884
0
    case IDENT_DRAINING:
1885
0
      ident_drain(ident, &output, osize_p);
1886
0
    }
1887
0
    return 0;
1888
0
  }
1889
1890
0
  while (*isize_p || (ident->state == IDENT_DRAINING)) {
1891
0
    int ch;
1892
1893
0
    if (ident->state == IDENT_DRAINING) {
1894
0
      ident_drain(ident, &output, osize_p);
1895
0
      if (!*osize_p)
1896
0
        break;
1897
0
      continue;
1898
0
    }
1899
1900
0
    ch = *(input++);
1901
0
    (*isize_p)--;
1902
1903
0
    if (ident->state == IDENT_SKIPPING) {
1904
      /*
1905
       * Skipping until '$' or LF, but keeping them
1906
       * in case it is a foreign ident.
1907
       */
1908
0
      strbuf_addch(&ident->left, ch);
1909
0
      if (ch != '\n' && ch != '$')
1910
0
        continue;
1911
0
      if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
1912
0
        strbuf_setlen(&ident->left, sizeof(head) - 1);
1913
0
        strbuf_addstr(&ident->left, ident->ident);
1914
0
      }
1915
0
      ident->state = IDENT_DRAINING;
1916
0
      continue;
1917
0
    }
1918
1919
0
    if (ident->state < sizeof(head) &&
1920
0
        head[ident->state] == ch) {
1921
0
      ident->state++;
1922
0
      continue;
1923
0
    }
1924
1925
0
    if (ident->state)
1926
0
      strbuf_add(&ident->left, head, ident->state);
1927
0
    if (ident->state == sizeof(head) - 1) {
1928
0
      if (ch != ':' && ch != '$') {
1929
0
        strbuf_addch(&ident->left, ch);
1930
0
        ident->state = 0;
1931
0
        continue;
1932
0
      }
1933
1934
0
      if (ch == ':') {
1935
0
        strbuf_addch(&ident->left, ch);
1936
0
        ident->state = IDENT_SKIPPING;
1937
0
      } else {
1938
0
        strbuf_addstr(&ident->left, ident->ident);
1939
0
        ident->state = IDENT_DRAINING;
1940
0
      }
1941
0
      continue;
1942
0
    }
1943
1944
0
    strbuf_addch(&ident->left, ch);
1945
0
    ident->state = IDENT_DRAINING;
1946
0
  }
1947
0
  return 0;
1948
0
}
1949
1950
static void ident_free_fn(struct stream_filter *filter)
1951
0
{
1952
0
  struct ident_filter *ident = (struct ident_filter *)filter;
1953
0
  strbuf_release(&ident->left);
1954
0
  free(filter);
1955
0
}
1956
1957
static struct stream_filter_vtbl ident_vtbl = {
1958
  .filter = ident_filter_fn,
1959
  .free = ident_free_fn,
1960
};
1961
1962
static struct stream_filter *ident_filter(const struct object_id *oid)
1963
0
{
1964
0
  struct ident_filter *ident = xmalloc(sizeof(*ident));
1965
1966
0
  xsnprintf(ident->ident, sizeof(ident->ident),
1967
0
      ": %s $", oid_to_hex(oid));
1968
0
  strbuf_init(&ident->left, 0);
1969
0
  ident->filter.vtbl = &ident_vtbl;
1970
0
  ident->state = 0;
1971
0
  return (struct stream_filter *)ident;
1972
0
}
1973
1974
/*
1975
 * Return an appropriately constructed filter for the given ca, or NULL if
1976
 * the contents cannot be filtered without reading the whole thing
1977
 * in-core.
1978
 *
1979
 * Note that you would be crazy to set CRLF, smudge/clean or ident to a
1980
 * large binary blob you would want us not to slurp into the memory!
1981
 */
1982
struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
1983
             const struct object_id *oid)
1984
0
{
1985
0
  struct stream_filter *filter = NULL;
1986
1987
0
  if (classify_conv_attrs(ca) != CA_CLASS_STREAMABLE)
1988
0
    return NULL;
1989
1990
0
  if (ca->ident)
1991
0
    filter = ident_filter(oid);
1992
1993
0
  if (output_eol(ca->crlf_action) == EOL_CRLF)
1994
0
    filter = cascade_filter(filter, lf_to_crlf_filter());
1995
0
  else
1996
0
    filter = cascade_filter(filter, &null_filter_singleton);
1997
1998
0
  return filter;
1999
0
}
2000
2001
struct stream_filter *get_stream_filter(struct index_state *istate,
2002
          const char *path,
2003
          const struct object_id *oid)
2004
0
{
2005
0
  struct conv_attrs ca;
2006
0
  convert_attrs(istate, &ca, path);
2007
0
  return get_stream_filter_ca(&ca, oid);
2008
0
}
2009
2010
void free_stream_filter(struct stream_filter *filter)
2011
0
{
2012
0
  filter->vtbl->free(filter);
2013
0
}
2014
2015
int stream_filter(struct stream_filter *filter,
2016
      const char *input, size_t *isize_p,
2017
      char *output, size_t *osize_p)
2018
0
{
2019
0
  return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
2020
0
}
2021
2022
void init_checkout_metadata(struct checkout_metadata *meta, const char *refname,
2023
          const struct object_id *treeish,
2024
          const struct object_id *blob)
2025
0
{
2026
0
  memset(meta, 0, sizeof(*meta));
2027
0
  if (refname)
2028
0
    meta->refname = refname;
2029
0
  if (treeish)
2030
0
    oidcpy(&meta->treeish, treeish);
2031
0
  if (blob)
2032
0
    oidcpy(&meta->blob, blob);
2033
0
}
2034
2035
void clone_checkout_metadata(struct checkout_metadata *dst,
2036
           const struct checkout_metadata *src,
2037
           const struct object_id *blob)
2038
0
{
2039
0
  memcpy(dst, src, sizeof(*dst));
2040
0
  if (blob)
2041
0
    oidcpy(&dst->blob, blob);
2042
0
}
2043
2044
enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca)
2045
0
{
2046
0
  if (ca->drv) {
2047
0
    if (ca->drv->process)
2048
0
      return CA_CLASS_INCORE_PROCESS;
2049
0
    if (ca->drv->smudge || ca->drv->clean)
2050
0
      return CA_CLASS_INCORE_FILTER;
2051
0
  }
2052
2053
0
  if (ca->working_tree_encoding)
2054
0
    return CA_CLASS_INCORE;
2055
2056
0
  if (ca->crlf_action == CRLF_AUTO || ca->crlf_action == CRLF_AUTO_CRLF)
2057
0
    return CA_CLASS_INCORE;
2058
2059
0
  return CA_CLASS_STREAMABLE;
2060
0
}