]> git.ipfire.org Git - thirdparty/git.git/blobdiff - convert.c
diagnose: add to command-list.txt
[thirdparty/git.git] / convert.c
index 9ecc1c699c087ecc270d7a45c11f6a8b9a183201..95e6a5244fc26c029abff85bb37a4e9fae71acba 100644 (file)
--- a/convert.c
+++ b/convert.c
 #define CONVERT_STAT_BITS_TXT_CRLF  0x2
 #define CONVERT_STAT_BITS_BIN       0x4
 
-enum crlf_action {
-       CRLF_UNDEFINED,
-       CRLF_BINARY,
-       CRLF_TEXT,
-       CRLF_TEXT_INPUT,
-       CRLF_TEXT_CRLF,
-       CRLF_AUTO,
-       CRLF_AUTO_INPUT,
-       CRLF_AUTO_CRLF
-};
-
 struct text_stat {
        /* NUL, CR, LF and CRLF counts */
        unsigned nul, lonecr, lonelf, crlf;
@@ -138,7 +127,7 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si
        }
 }
 
-const char *get_cached_convert_stats_ascii(const struct index_state *istate,
+const char *get_cached_convert_stats_ascii(struct index_state *istate,
                                           const char *path)
 {
        const char *ret;
@@ -172,7 +161,7 @@ static int text_eol_is_crlf(void)
        return 0;
 }
 
-static enum eol output_eol(enum crlf_action crlf_action)
+static enum eol output_eol(enum convert_crlf_action crlf_action)
 {
        switch (crlf_action) {
        case CRLF_BINARY:
@@ -206,9 +195,9 @@ static void check_global_conv_flags_eol(const char *path,
                if (conv_flags & CONV_EOL_RNDTRP_DIE)
                        die(_("CRLF would be replaced by LF in %s"), path);
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
-                       warning(_("CRLF will be replaced by LF in %s.\n"
-                                 "The file will have its original line"
-                                 " endings in your working directory"), path);
+                       warning(_("in the working copy of '%s', CRLF will be"
+                                 " replaced by LF the next time Git touches"
+                                 " it"), path);
        } else if (old_stats->lonelf && !new_stats->lonelf ) {
                /*
                 * CRLFs would be added by checkout
@@ -216,13 +205,13 @@ static void check_global_conv_flags_eol(const char *path,
                if (conv_flags & CONV_EOL_RNDTRP_DIE)
                        die(_("LF would be replaced by CRLF in %s"), path);
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
-                       warning(_("LF will be replaced by CRLF in %s.\n"
-                                 "The file will have its original line"
-                                 " endings in your working directory"), path);
+                       warning(_("in the working copy of '%s', LF will be"
+                                 " replaced by CRLF the next time Git touches"
+                                 " it"), path);
        }
 }
 
-static int has_crlf_in_index(const struct index_state *istate, const char *path)
+static int has_crlf_in_index(struct index_state *istate, const char *path)
 {
        unsigned long sz;
        void *data;
@@ -246,7 +235,7 @@ static int has_crlf_in_index(const struct index_state *istate, const char *path)
 }
 
 static int will_convert_lf_to_crlf(struct text_stat *stats,
-                                  enum crlf_action crlf_action)
+                                  enum convert_crlf_action crlf_action)
 {
        if (output_eol(crlf_action) != EOL_CRLF)
                return 0;
@@ -496,10 +485,10 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len,
        return 1;
 }
 
-static int crlf_to_git(const struct index_state *istate,
+static int crlf_to_git(struct index_state *istate,
                       const char *path, const char *src, size_t len,
                       struct strbuf *buf,
-                      enum crlf_action crlf_action, int conv_flags)
+                      enum convert_crlf_action crlf_action, int conv_flags)
 {
        struct text_stat stats;
        char *dst;
@@ -585,8 +574,8 @@ static int crlf_to_git(const struct index_state *istate,
        return 1;
 }
 
-static int crlf_to_worktree(const char *src, size_t len,
-                           struct strbuf *buf, enum crlf_action crlf_action)
+static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf,
+                           enum convert_crlf_action crlf_action)
 {
        char *to_free = NULL;
        struct text_stat stats;
@@ -624,13 +613,13 @@ static int crlf_to_worktree(const char *src, size_t len,
 
 struct filter_params {
        const char *src;
-       unsigned long size;
+       size_t size;
        int fd;
        const char *cmd;
        const char *path;
 };
 
-static int filter_buffer_or_fd(int in, int out, void *data)
+static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
 {
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
@@ -884,9 +873,13 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
                goto done;
 
        if (fd >= 0)
-               err = write_packetized_from_fd(fd, process->in);
+               err = write_packetized_from_fd_no_flush(fd, process->in);
        else
-               err = write_packetized_from_buf(src, len, process->in);
+               err = write_packetized_from_buf_no_flush(src, len, process->in);
+       if (err)
+               goto done;
+
+       err = packet_flush_gently(process->in);
        if (err)
                goto done;
 
@@ -903,7 +896,8 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
                if (err)
                        goto done;
 
-               err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
+               err = read_packetized_to_strbuf(process->out, &nbuf,
+                                               PACKET_READ_GENTLE_ON_EOF) < 0;
                if (err)
                        goto done;
 
@@ -922,6 +916,7 @@ done:
        else
                strbuf_swap(dst, &nbuf);
        strbuf_release(&nbuf);
+       strbuf_release(&filter_status);
        return !err;
 }
 
@@ -972,6 +967,7 @@ done:
 
        if (err)
                handle_filter_error(&filter_status, entry, 0);
+       strbuf_release(&filter_status);
        return !err;
 }
 
@@ -1012,7 +1008,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        return 0;
 }
 
-static int read_convert_config(const char *var, const char *value, void *cb)
+static int read_convert_config(const char *var, const char *value, void *cb UNUSED)
 {
        const char *key, *name;
        size_t namelen;
@@ -1163,7 +1159,7 @@ static int ident_to_worktree(const char *src, size_t len,
        /* are we "faking" in place editing ? */
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
-       hash_object_file(the_hash_algo, src, len, "blob", &oid);
+       hash_object_file(the_hash_algo, src, len, OBJ_BLOB, &oid);
 
        strbuf_grow(buf, len + cnt * (the_hash_algo->hexsz + 3));
        for (;;) {
@@ -1247,7 +1243,7 @@ static const char *git_path_check_encoding(struct attr_check_item *check)
        return value;
 }
 
-static enum crlf_action git_path_check_crlf(struct attr_check_item *check)
+static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check)
 {
        const char *value = check->value;
 
@@ -1297,18 +1293,10 @@ static int git_path_check_ident(struct attr_check_item *check)
        return !!ATTR_TRUE(value);
 }
 
-struct conv_attrs {
-       struct convert_driver *drv;
-       enum crlf_action attr_action; /* What attr says */
-       enum crlf_action crlf_action; /* When no attr is set, use core.autocrlf */
-       int ident;
-       const char *working_tree_encoding; /* Supported encoding or default encoding if NULL */
-};
-
 static struct attr_check *check;
 
-static void convert_attrs(const struct index_state *istate,
-                         struct conv_attrs *ca, const char *path)
+void convert_attrs(struct index_state *istate,
+                  struct conv_attrs *ca, const char *path)
 {
        struct attr_check_item *ccheck = NULL;
 
@@ -1369,7 +1357,7 @@ void reset_parsed_attributes(void)
        user_convert_tail = NULL;
 }
 
-int would_convert_to_git_filter_fd(const struct index_state *istate, const char *path)
+int would_convert_to_git_filter_fd(struct index_state *istate, const char *path)
 {
        struct conv_attrs ca;
 
@@ -1388,7 +1376,7 @@ int would_convert_to_git_filter_fd(const struct index_state *istate, const char
        return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL, NULL);
 }
 
-const char *get_convert_attr_ascii(const struct index_state *istate, const char *path)
+const char *get_convert_attr_ascii(struct index_state *istate, const char *path)
 {
        struct conv_attrs ca;
 
@@ -1414,7 +1402,7 @@ const char *get_convert_attr_ascii(const struct index_state *istate, const char
        return "";
 }
 
-int convert_to_git(const struct index_state *istate,
+int convert_to_git(struct index_state *istate,
                   const char *path, const char *src, size_t len,
                   struct strbuf *dst, int conv_flags)
 {
@@ -1448,7 +1436,7 @@ int convert_to_git(const struct index_state *istate,
        return ret | ident_to_git(src, len, dst, ca.ident);
 }
 
-void convert_to_git_filter_fd(const struct index_state *istate,
+void convert_to_git_filter_fd(struct index_state *istate,
                              const char *path, int fd, struct strbuf *dst,
                              int conv_flags)
 {
@@ -1456,7 +1444,6 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        convert_attrs(istate, &ca, path);
 
        assert(ca.drv);
-       assert(ca.drv->clean || ca.drv->process);
 
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL))
                die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
@@ -1466,19 +1453,16 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        ident_to_git(dst->buf, dst->len, dst, ca.ident);
 }
 
-static int convert_to_working_tree_internal(const struct index_state *istate,
-                                           const char *path, const char *src,
-                                           size_t len, struct strbuf *dst,
-                                           int normalizing,
-                                           const struct checkout_metadata *meta,
-                                           struct delayed_checkout *dco)
+static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
+                                              const char *path, const char *src,
+                                              size_t len, struct strbuf *dst,
+                                              int normalizing,
+                                              const struct checkout_metadata *meta,
+                                              struct delayed_checkout *dco)
 {
        int ret = 0, ret_filter = 0;
-       struct conv_attrs ca;
 
-       convert_attrs(istate, &ca, path);
-
-       ret |= ident_to_worktree(src, len, dst, ca.ident);
+       ret |= ident_to_worktree(src, len, dst, ca->ident);
        if (ret) {
                src = dst->buf;
                len = dst->len;
@@ -1488,49 +1472,56 @@ static int convert_to_working_tree_internal(const struct index_state *istate,
         * is a smudge or process filter (even if the process filter doesn't
         * support smudge).  The filters might expect CRLFs.
         */
-       if ((ca.drv && (ca.drv->smudge || ca.drv->process)) || !normalizing) {
-               ret |= crlf_to_worktree(src, len, dst, ca.crlf_action);
+       if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) {
+               ret |= crlf_to_worktree(src, len, dst, ca->crlf_action);
                if (ret) {
                        src = dst->buf;
                        len = dst->len;
                }
        }
 
-       ret |= encode_to_worktree(path, src, len, dst, ca.working_tree_encoding);
+       ret |= encode_to_worktree(path, src, len, dst, ca->working_tree_encoding);
        if (ret) {
                src = dst->buf;
                len = dst->len;
        }
 
        ret_filter = apply_filter(
-               path, src, len, -1, dst, ca.drv, CAP_SMUDGE, meta, dco);
-       if (!ret_filter && ca.drv && ca.drv->required)
-               die(_("%s: smudge filter %s failed"), path, ca.drv->name);
+               path, src, len, -1, dst, ca->drv, CAP_SMUDGE, meta, dco);
+       if (!ret_filter && ca->drv && ca->drv->required)
+               die(_("%s: smudge filter %s failed"), path, ca->drv->name);
 
        return ret | ret_filter;
 }
 
-int async_convert_to_working_tree(const struct index_state *istate,
-                                 const char *path, const char *src,
-                                 size_t len, struct strbuf *dst,
-                                 const struct checkout_metadata *meta,
-                                 void *dco)
+int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
+                                    const char *path, const char *src,
+                                    size_t len, struct strbuf *dst,
+                                    const struct checkout_metadata *meta,
+                                    void *dco)
 {
-       return convert_to_working_tree_internal(istate, path, src, len, dst, 0, meta, dco);
+       return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
+                                                  meta, dco);
 }
 
-int convert_to_working_tree(const struct index_state *istate,
-                           const char *path, const char *src,
-                           size_t len, struct strbuf *dst,
-                           const struct checkout_metadata *meta)
+int convert_to_working_tree_ca(const struct conv_attrs *ca,
+                              const char *path, const char *src,
+                              size_t len, struct strbuf *dst,
+                              const struct checkout_metadata *meta)
 {
-       return convert_to_working_tree_internal(istate, path, src, len, dst, 0, meta, NULL);
+       return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
+                                                  meta, NULL);
 }
 
-int renormalize_buffer(const struct index_state *istate, const char *path,
+int renormalize_buffer(struct index_state *istate, const char *path,
                       const char *src, size_t len, struct strbuf *dst)
 {
-       int ret = convert_to_working_tree_internal(istate, path, src, len, dst, 1, NULL, NULL);
+       struct conv_attrs ca;
+       int ret;
+
+       convert_attrs(istate, &ca, path);
+       ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1,
+                                                 NULL, NULL);
        if (ret) {
                src = dst->buf;
                len = dst->len;
@@ -1583,12 +1574,12 @@ static void null_free_fn(struct stream_filter *filter)
 }
 
 static struct stream_filter_vtbl null_vtbl = {
-       null_filter_fn,
-       null_free_fn,
+       .filter = null_filter_fn,
+       .free = null_free_fn,
 };
 
 static struct stream_filter null_filter_singleton = {
-       &null_vtbl,
+       .vtbl = &null_vtbl,
 };
 
 int is_null_stream_filter(struct stream_filter *filter)
@@ -1692,8 +1683,8 @@ static void lf_to_crlf_free_fn(struct stream_filter *filter)
 }
 
 static struct stream_filter_vtbl lf_to_crlf_vtbl = {
-       lf_to_crlf_filter_fn,
-       lf_to_crlf_free_fn,
+       .filter = lf_to_crlf_filter_fn,
+       .free = lf_to_crlf_free_fn,
 };
 
 static struct stream_filter *lf_to_crlf_filter(void)
@@ -1788,8 +1779,8 @@ static void cascade_free_fn(struct stream_filter *filter)
 }
 
 static struct stream_filter_vtbl cascade_vtbl = {
-       cascade_filter_fn,
-       cascade_free_fn,
+       .filter = cascade_filter_fn,
+       .free = cascade_free_fn,
 };
 
 static struct stream_filter *cascade_filter(struct stream_filter *one,
@@ -1940,8 +1931,8 @@ static void ident_free_fn(struct stream_filter *filter)
 }
 
 static struct stream_filter_vtbl ident_vtbl = {
-       ident_filter_fn,
-       ident_free_fn,
+       .filter = ident_filter_fn,
+       .free = ident_free_fn,
 };
 
 static struct stream_filter *ident_filter(const struct object_id *oid)
@@ -1957,34 +1948,25 @@ static struct stream_filter *ident_filter(const struct object_id *oid)
 }
 
 /*
- * Return an appropriately constructed filter for the path, or NULL if
+ * Return an appropriately constructed filter for the given ca, or NULL if
  * the contents cannot be filtered without reading the whole thing
  * in-core.
  *
  * Note that you would be crazy to set CRLF, smudge/clean or ident to a
  * large binary blob you would want us not to slurp into the memory!
  */
-struct stream_filter *get_stream_filter(const struct index_state *istate,
-                                       const char *path,
-                                       const struct object_id *oid)
+struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
+                                          const struct object_id *oid)
 {
-       struct conv_attrs ca;
        struct stream_filter *filter = NULL;
 
-       convert_attrs(istate, &ca, path);
-       if (ca.drv && (ca.drv->process || ca.drv->smudge || ca.drv->clean))
+       if (classify_conv_attrs(ca) != CA_CLASS_STREAMABLE)
                return NULL;
 
-       if (ca.working_tree_encoding)
-               return NULL;
-
-       if (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)
-               return NULL;
-
-       if (ca.ident)
+       if (ca->ident)
                filter = ident_filter(oid);
 
-       if (output_eol(ca.crlf_action) == EOL_CRLF)
+       if (output_eol(ca->crlf_action) == EOL_CRLF)
                filter = cascade_filter(filter, lf_to_crlf_filter());
        else
                filter = cascade_filter(filter, &null_filter_singleton);
@@ -1992,6 +1974,15 @@ struct stream_filter *get_stream_filter(const struct index_state *istate,
        return filter;
 }
 
+struct stream_filter *get_stream_filter(struct index_state *istate,
+                                       const char *path,
+                                       const struct object_id *oid)
+{
+       struct conv_attrs ca;
+       convert_attrs(istate, &ca, path);
+       return get_stream_filter_ca(&ca, oid);
+}
+
 void free_stream_filter(struct stream_filter *filter)
 {
        filter->vtbl->free(filter);
@@ -2025,3 +2016,21 @@ void clone_checkout_metadata(struct checkout_metadata *dst,
        if (blob)
                oidcpy(&dst->blob, blob);
 }
+
+enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca)
+{
+       if (ca->drv) {
+               if (ca->drv->process)
+                       return CA_CLASS_INCORE_PROCESS;
+               if (ca->drv->smudge || ca->drv->clean)
+                       return CA_CLASS_INCORE_FILTER;
+       }
+
+       if (ca->working_tree_encoding)
+               return CA_CLASS_INCORE;
+
+       if (ca->crlf_action == CRLF_AUTO || ca->crlf_action == CRLF_AUTO_CRLF)
+               return CA_CLASS_INCORE;
+
+       return CA_CLASS_STREAMABLE;
+}