Coverage Report

Created: 2024-09-08 06:23

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