From 265fe63b137e6ed1426f646a30b55c2cc7ef7cff Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Tue, 17 Mar 2026 00:11:14 -0400 Subject: [PATCH 01/12] skip tagging the file with the target encoding if the conversion fails --- stable-patches/convert.c.patch | 8 +++++--- stable-patches/convert.h.patch | 2 +- stable-patches/diff.c.patch | 14 +++++++++++--- stable-patches/entry.c.patch | 4 ++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index 586e967..f583bf7 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -163,12 +163,14 @@ index c7d6a85..f3db530 100644 + +#ifdef __MVS__ + -+void tag_file_as_working_tree_encoding(struct index_state *istate, char* path, int fd) { ++void tag_file_as_working_tree_encoding(struct index_state *istate, const char* path, int fd, int was_converted) { + struct conv_attrs ca; + convert_attrs(istate, &ca, path); + if (ca.attr_action != CRLF_BINARY) { -+ if (ca.working_tree_encoding) -+ __chgfdcodeset(fd, ca.working_tree_encoding); ++ if (ca.working_tree_encoding) { ++ if (was_converted) ++ __chgfdcodeset(fd, ca.working_tree_encoding); ++ } + else + __chgfdccsid(fd, utf8_ccsid); + } diff --git a/stable-patches/convert.h.patch b/stable-patches/convert.h.patch index ed4a3f2..a9d8a81 100644 --- a/stable-patches/convert.h.patch +++ b/stable-patches/convert.h.patch @@ -7,7 +7,7 @@ index 0a6e408..dcab447 100644 const struct conv_attrs *ca); +#ifdef __MVS__ -+void tag_file_as_working_tree_encoding(struct index_state *istate, char* path, int fd); ++void tag_file_as_working_tree_encoding(struct index_state *istate, const char* path, int fd, int was_converted); +void validate_codeset(struct index_state *istate, const char *path, int* autoconvertToASCII); +#endif + diff --git a/stable-patches/diff.c.patch b/stable-patches/diff.c.patch index 5c50ec0..72b23fd 100644 --- a/stable-patches/diff.c.patch +++ b/stable-patches/diff.c.patch @@ -1,5 +1,5 @@ diff --git a/diff.c b/diff.c -index a68ddd2..689cc66 100644 +index a68ddd2..48ccc6b 100644 --- a/diff.c +++ b/diff.c @@ -4194,6 +4194,7 @@ int diff_populate_filespec(struct repository *r, @@ -29,13 +29,21 @@ index a68ddd2..689cc66 100644 s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); s->should_munmap = 1; -@@ -4374,6 +4384,10 @@ static void prep_temp_blob(struct index_state *istate, +@@ -4369,11 +4379,16 @@ static void prep_temp_blob(struct index_state *istate, + temp->tempfile = mks_tempfile_dt("git-blob-XXXXXX", base); + if (!temp->tempfile) + die_errno("unable to create temp-file"); +- if (convert_to_working_tree(istate, path, +- (const char *)blob, (size_t)size, &buf, &meta)) { ++ int ret = convert_to_working_tree(istate, path, ++ (const char *)blob, (size_t)size, &buf, &meta); ++ if (ret) { blob = buf.buf; size = buf.len; } + +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(istate, path, temp->tempfile->fd); ++ tag_file_as_working_tree_encoding(istate, path, temp->tempfile->fd, ret); +#endif if (write_in_full(temp->tempfile->fd, blob, size) < 0 || close_tempfile_gently(temp->tempfile)) diff --git a/stable-patches/entry.c.patch b/stable-patches/entry.c.patch index 9060b57..a8c5d5a 100644 --- a/stable-patches/entry.c.patch +++ b/stable-patches/entry.c.patch @@ -7,7 +7,7 @@ index 7817aee..d2ca664 100644 return -1; +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(state->istate, path, fd); ++ tag_file_as_working_tree_encoding(state->istate, path, fd, 1); +#endif + result |= odb_stream_blob_to_fd(the_repository->objects, fd, &ce->oid, filter, 1); @@ -18,7 +18,7 @@ index 7817aee..d2ca664 100644 } +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(state->istate, path, fd); ++ tag_file_as_working_tree_encoding(state->istate, path, fd, ret); +#endif + wrote = write_in_full(fd, new_blob, size); From b6fe1248cdad9b54714f806f04f2cc8ccb7db1dd Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Mon, 6 Apr 2026 00:48:19 -0400 Subject: [PATCH 02/12] enable more descriptive error reporting , handling of iconv errors during add and clone --- buildenv | 13 +- stable-patches/apply.c.patch | 37 +++ stable-patches/archive.c.patch | 12 +- stable-patches/builtin/cat-file.c.patch | 14 ++ stable-patches/builtin/index-pack.c.patch | 32 +++ stable-patches/combine-diff.c.patch | 11 +- stable-patches/common-init.c.patch | 0 stable-patches/config.mak.uname.patch | 11 +- stable-patches/convert.c.patch | 151 +++++++++-- stable-patches/copy.c.patch | 8 +- stable-patches/diff.c.patch | 26 +- stable-patches/entry.c.patch | 86 ++++++- stable-patches/hash-object.c.patch | 12 +- stable-patches/lockfile.c.patch | 9 +- stable-patches/object-file.c.patch | 275 ++++++++++++++++++++- stable-patches/odb.c.patch | 219 +++++++++++++++- stable-patches/pack-write.c.patch | 26 ++ stable-patches/parallel-checkout.c.patch | 46 ++++ stable-patches/repository.c.patch | 27 +- stable-patches/run-command.c.patch | 86 +++++++ stable-patches/t-meson.build.patch | 12 + stable-patches/t0082-zos-encoding.sh.patch | 55 +++++ 22 files changed, 1097 insertions(+), 71 deletions(-) create mode 100644 stable-patches/apply.c.patch create mode 100644 stable-patches/builtin/cat-file.c.patch create mode 100644 stable-patches/builtin/index-pack.c.patch create mode 100644 stable-patches/common-init.c.patch create mode 100644 stable-patches/pack-write.c.patch create mode 100644 stable-patches/parallel-checkout.c.patch create mode 100644 stable-patches/run-command.c.patch create mode 100644 stable-patches/t-meson.build.patch create mode 100644 stable-patches/t0082-zos-encoding.sh.patch diff --git a/buildenv b/buildenv index 4040e79..0f07f6d 100644 --- a/buildenv +++ b/buildenv @@ -1,23 +1,24 @@ # export ZOPEN_BUILD_LINE="STABLE" export ZOPEN_CATEGORIES="development source_control" +export PERL_HOME="/home/haritha/zopen_23may/zopen/usr/local/zopen/perl/perl" # bump: git-version /GIT_VERSION="(.*)"/ https://github.com/git/git.git|* GIT_VERSION="2.53.0" export ZOPEN_DEV_URL="https://github.com/git/git.git" -export ZOPEN_DEV_DEPS="curl git make m4 perl autoconf automake help2man texinfo xz zlib openssl expat gettext coreutils diffutils bash tar check_python gawk zusage libpsl libssh2" +export ZOPEN_DEV_DEPS="curl git make m4 perl autoconf automake help2man texinfo xz zlib openssl expat gettext coreutils diffutils bash tar check_python gawk zusage libpsl libssh2 libiconv" export ZOPEN_STABLE_URL="https://github.com/git/git.git" export ZOPEN_STABLE_TAG="v${GIT_VERSION}" -export ZOPEN_STABLE_DEPS="curl git make m4 perl autoconf automake help2man texinfo xz zlib openssl expat gettext gzip tar coreutils zoslib diffutils ncurses bash sed libpcre2 tar check_python gawk zusage libpsl libssh2" +export ZOPEN_STABLE_DEPS="curl git make m4 perl autoconf automake help2man texinfo xz zlib openssl expat gettext gzip tar coreutils zoslib diffutils ncurses bash sed libpcre2 tar check_python gawk zusage libpsl libssh2 libiconv" # # Note the 'man' tarball release is numbered independently from the 'git' release. # export ZOPEN_TARBALL_MAN_URL="https://mirrors.edge.kernel.org/pub/software/scm/git/git-manpages-${GIT_VERSION}.tar.xz" -export ZOPEN_RUNTIME_DEPS="perl bash less ncurses" # If building with shared libs, add openssl, curl +export ZOPEN_RUNTIME_DEPS="perl bash less ncurses libiconv" # If building with shared libs, add openssl, curl export ZOPEN_BOOTSTRAP="make" export ZOPEN_BOOTSTRAP_OPTS="configure" @@ -30,10 +31,10 @@ export ZOPEN_INSTALL_OPTS="" export ZOPEN_CHECK_OPTS="test -j\$ZOPEN_NUM_JOBS" export ZOPEN_COMP=CLANG -export ZOPEN_EXTRA_CONFIGURE_OPTS="--with-zlib=\${ZLIB_HOME} --with-curl=\${CURL_HOME} --with-openssl=\${OPENSSL_HOME} --with-libpcre2=\${PCRE2_HOME}" +export ZOPEN_EXTRA_CONFIGURE_OPTS="--with-zlib=\${ZLIB_HOME} --with-curl=\${CURL_HOME} --with-openssl=\${OPENSSL_HOME} --with-libpcre2=\${PCRE2_HOME} --with-libiconv-prefix=\${LIBICONV_HOME}" -export ZOPEN_EXTRA_CPPFLAGS="-I\${OPENSSL_HOME}/include -I\${GETTEXT_HOME}/include -I\${ZLIB_HOME}/include -I\${NCURSES_HOME}/include -I\${ZOPEN_ROOT}/patches/include -I\${CURL_HOME}/include -I\${EXPAT_HOME}/include" -export ZOPEN_EXTRA_LDFLAGS="-L\${GETTEXT_HOME}/lib -L\${OPENSSL_HOME}/lib -L\${ZLIB_HOME}/lib -L\${NCURSES_HOME}/lib -L\${CURL_HOME}/lib -L\${EXPAT_HOME}/lib" +export ZOPEN_EXTRA_CPPFLAGS="-I\${OPENSSL_HOME}/include -I\${GETTEXT_HOME}/include -I\${ZLIB_HOME}/include -I\${NCURSES_HOME}/include -I\${ZOPEN_ROOT}/patches/include -I\${CURL_HOME}/include -I\${EXPAT_HOME}/include -I\${LIBICONV_HOME}/include" +export ZOPEN_EXTRA_LDFLAGS="-L\${GETTEXT_HOME}/lib -L\${OPENSSL_HOME}/lib -L\${ZLIB_HOME}/lib -L\${NCURSES_HOME}/lib -L\${CURL_HOME}/lib -L\${EXPAT_HOME}/lib -L\${LIBICONV_HOME}/lib" export ZOPEN_EXTRA_LIBS="${ZOPEN_EXTRA_LIBS} -lz -lcurl -lssl -lcrypto" export ZOPEN_EXTRA_CFLAGS="-mzos-target=zosv2r5 -march=z13" export ZOPEN_SYSTEM_PREREQS="zos25" diff --git a/stable-patches/apply.c.patch b/stable-patches/apply.c.patch new file mode 100644 index 0000000..58b747d --- /dev/null +++ b/stable-patches/apply.c.patch @@ -0,0 +1,37 @@ +diff --git a/apply.c b/apply.c +index 3de4aa4..031a6e1 100644 +--- a/apply.c ++++ b/apply.c +@@ -33,6 +33,7 @@ + #include "read-cache.h" + #include "repository.h" + #include "rerere.h" ++#include "convert.h" + #include "apply.h" + #include "entry.h" + #include "setup.h" +@@ -4446,12 +4447,23 @@ static int try_create_file(struct apply_state *state, const char *path, + if (fd < 0) + return 1; + +- if (convert_to_working_tree(state->repo->index, path, buf, size, &nbuf, NULL)) { ++#ifdef __MVS__ ++ __setfdbinary(fd); ++ __disableautocvt(fd); ++#endif ++ ++ int ret = convert_to_working_tree(state->repo->index, path, buf, size, &nbuf, NULL); ++ if (ret > 0) { + size = nbuf.len; + buf = nbuf.buf; + } + + res = write_in_full(fd, buf, size) < 0; ++ ++#ifdef __MVS__ ++ tag_file_as_working_tree_encoding(state->repo->index, path, fd, ret); ++#endif ++ + if (res) + error_errno(_("failed to write to '%s'"), path); + strbuf_release(&nbuf); diff --git a/stable-patches/archive.c.patch b/stable-patches/archive.c.patch index c4a8e57..e42a504 100644 --- a/stable-patches/archive.c.patch +++ b/stable-patches/archive.c.patch @@ -1,14 +1,18 @@ diff --git a/builtin/archive.c b/builtin/archive.c -index 13ea730..f0da605 100644 +index 13ea730..d45ce03 100644 --- a/builtin/archive.c +++ b/builtin/archive.c -@@ -12,6 +12,10 @@ +@@ -12,6 +12,14 @@ static void create_output_file(const char *output_file) { int output_fd = xopen(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666); +#ifdef __MVS__ -+ if (__setfdbinary(output_fd)) -+ die_errno(_("could not tag archive file '%s'"), output_file); ++ struct stat st; ++ if (fstat(output_fd, &st) >= 0 && S_ISREG(st.st_mode)) { ++ if (__setfdbinary(output_fd)) ++ die_errno(_("could not tag archive file '%s'"), output_file); ++ __disableautocvt(output_fd); ++ } +#endif if (output_fd != 1) { if (dup2(output_fd, 1) < 0) diff --git a/stable-patches/builtin/cat-file.c.patch b/stable-patches/builtin/cat-file.c.patch new file mode 100644 index 0000000..b278bc5 --- /dev/null +++ b/stable-patches/builtin/cat-file.c.patch @@ -0,0 +1,14 @@ +diff --git a/builtin/cat-file.c b/builtin/cat-file.c +index df8e87a..d40b845 100644 +--- a/builtin/cat-file.c ++++ b/builtin/cat-file.c +@@ -83,7 +83,8 @@ static int filter_object(const char *path, unsigned mode, + struct checkout_metadata meta; + + init_checkout_metadata(&meta, NULL, NULL, oid); +- if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) { ++ int ret = convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta); ++ if (ret > 0) { + free(*buf); + *size = strbuf.len; + *buf = strbuf_detach(&strbuf, NULL); diff --git a/stable-patches/builtin/index-pack.c.patch b/stable-patches/builtin/index-pack.c.patch new file mode 100644 index 0000000..8c6bd06 --- /dev/null +++ b/stable-patches/builtin/index-pack.c.patch @@ -0,0 +1,32 @@ +diff --git a/builtin/index-pack.c b/builtin/index-pack.c +index b67fb02..1918ff3 100644 +--- a/builtin/index-pack.c ++++ b/builtin/index-pack.c +@@ -212,6 +212,9 @@ static void init_thread(void) + CALLOC_ARRAY(thread_data, nr_threads); + for (i = 0; i < nr_threads; i++) { + thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY); ++#ifdef __MVS__ ++ __disableautocvt(thread_data[i].pack_fd); ++#endif + } + + threads_active = 1; +@@ -368,10 +371,17 @@ static const char *open_pack_file(const char *pack_name) + pack_name = strbuf_detach(&tmp_file, NULL); + } else { + output_fd = xopen(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); ++#ifdef __MVS__ ++ __setfdbinary(output_fd); ++ __disableautocvt(output_fd); ++#endif + } + nothread_data.pack_fd = output_fd; + } else { + input_fd = xopen(pack_name, O_RDONLY); ++#ifdef __MVS__ ++ __disableautocvt(input_fd); ++#endif + output_fd = -1; + nothread_data.pack_fd = input_fd; + } diff --git a/stable-patches/combine-diff.c.patch b/stable-patches/combine-diff.c.patch index d85294c..be08a67 100644 --- a/stable-patches/combine-diff.c.patch +++ b/stable-patches/combine-diff.c.patch @@ -1,5 +1,5 @@ diff --git a/combine-diff.c b/combine-diff.c -index b799862..fc1ce24 100644 +index b799862..0fea1b9 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1074,6 +1074,10 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, @@ -13,3 +13,12 @@ index b799862..fc1ce24 100644 elem->mode = canon_mode(st.st_mode); /* if symlinks don't work, assume symlink if all parents * are symlinks +@@ -1098,7 +1102,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, + struct strbuf buf = STRBUF_INIT; + + if (convert_to_git(rev->diffopt.repo->index, +- elem->path, result, len, &buf, global_conv_flags_eol)) { ++ elem->path, result, len, &buf, global_conv_flags_eol) > 0) { + free(result); + result = strbuf_detach(&buf, &len); + result_size = len; diff --git a/stable-patches/common-init.c.patch b/stable-patches/common-init.c.patch new file mode 100644 index 0000000..e69de29 diff --git a/stable-patches/config.mak.uname.patch b/stable-patches/config.mak.uname.patch index fb8d79a..fcf69b9 100644 --- a/stable-patches/config.mak.uname.patch +++ b/stable-patches/config.mak.uname.patch @@ -2,15 +2,15 @@ diff --git a/config.mak.uname b/config.mak.uname index d5112168a4..17716314c0 100644 --- a/config.mak.uname +++ b/config.mak.uname -@@ -639,12 +639,19 @@ ifeq ($(uname_S),NONSTOP_KERNEL) +@@ -639,12 +639,21 @@ ifeq ($(uname_S),NONSTOP_KERNEL) SHELL_PATH = /usr/coreutils/bin/bash endif ifeq ($(uname_S),OS/390) -+ PERL_PATH = perl ++ PERL_PATH = $(PERL_HOME)/bin/perl + PERL_PATH_FOR_SCRIPTS = /bin/env perl -+ SHELL_PATH = bash ++ SHELL_PATH = $(BASH_HOME)/bin/bash + SHELL_PATH_FOR_SCRIPTS = /bin/env bash -+ PYTHON_PATH = python ++ PYTHON_PATH = /home/opnzos/local/pyz/bin/python NO_SYS_POLL_H = YesPlease + RUNTIME_PREFIX = YesPlease NO_STRCASESTR = YesPlease @@ -22,3 +22,6 @@ index d5112168a4..17716314c0 100644 NO_MEMMEM = YesPlease NO_GECOS_IN_PWENT = YesPlease HAVE_STRINGS_H = YesPlease ++ NEEDS_LIBICONV = YesPlease ++ ICONVDIR = $(LIBICONV_HOME) + endif diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index f583bf7..f321680 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -1,5 +1,5 @@ diff --git a/convert.c b/convert.c -index c7d6a85..f3db530 100644 +index c7d6a85..1c49d9f 100644 --- a/convert.c +++ b/convert.c @@ -6,6 +6,7 @@ @@ -52,17 +52,44 @@ index c7d6a85..f3db530 100644 dst = reencode_string_len(src, src_len, default_encoding, enc, &dst_len); if (!dst) { -@@ -420,6 +435,9 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -420,12 +435,32 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, * would fail and we would leave the user with a messed-up * working tree. Let's try to avoid this by screaming loud. */ +- const char* msg = _("failed to encode '%s' from %s to %s"); + if (attr_action == CRLF_BINARY) { + return 0; + } - const char* msg = _("failed to encode '%s' from %s to %s"); ++ size_t line = 1; ++ size_t col = 1; ++ unsigned char bad_char = 0; ++ for (size_t i = 0; i < src_len; i++) { ++ if (src[i] == '\n') { ++ line++; ++ col = 1; ++ } else { ++ col++; ++ } ++ /* Try to find the first character that iconv would reject */ ++ if ((unsigned char)src[i] > 0x7F) { ++ bad_char = (unsigned char)src[i]; ++ break; ++ } ++ } ++ ++ const char* msg = _("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"); if (die_on_error) - die(msg, path, enc, default_encoding); -@@ -476,10 +494,14 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +- die(msg, path, enc, default_encoding); ++ die(msg, path, enc, default_encoding, line, col, bad_char); + else { +- error(msg, path, enc, default_encoding); +- return 0; ++ error(msg, path, enc, default_encoding, line, col, bad_char); ++ return -1; + } + } + trace_encoding("destination", path, default_encoding, dst, dst_len); +@@ -476,10 +511,14 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, } static int encode_to_worktree(const char *path, const char *src, size_t src_len, @@ -78,7 +105,37 @@ index c7d6a85..f3db530 100644 /* * No encoding is specified or there is nothing to encode. -@@ -1316,18 +1338,40 @@ static int git_path_check_ident(struct attr_check_item *check) +@@ -491,9 +530,26 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len, + dst = reencode_string_len(src, src_len, enc, default_encoding, + &dst_len); + if (!dst) { +- error(_("failed to encode '%s' from %s to %s"), +- path, default_encoding, enc); +- return 0; ++ size_t line = 1; ++ size_t col = 1; ++ unsigned char bad_char = 0; ++ for (size_t i = 0; i < src_len; i++) { ++ if (src[i] == '\n') { ++ line++; ++ col = 1; ++ } else { ++ col++; ++ } ++ /* Try to find the first character that iconv would reject for IBM-1047 */ ++ /* (In a real implementation, we could call iconv in a loop here) */ ++ if ((unsigned char)src[i] > 0x7F) { ++ bad_char = (unsigned char)src[i]; ++ break; ++ } ++ } ++ error(_("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"), ++ path, default_encoding, enc, line, col, bad_char); ++ return -1; + } + + strbuf_attach(buf, dst, dst_len, dst_len + 1); +@@ -1316,18 +1372,40 @@ static int git_path_check_ident(struct attr_check_item *check) static struct attr_check *check; @@ -119,7 +176,7 @@ index c7d6a85..f3db530 100644 git_check_attr(istate, path, check); ccheck = check->items; -@@ -1348,6 +1392,8 @@ void convert_attrs(struct index_state *istate, +@@ -1348,6 +1426,8 @@ void convert_attrs(struct index_state *istate, ca->crlf_action = CRLF_TEXT_CRLF; } ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); @@ -128,16 +185,32 @@ index c7d6a85..f3db530 100644 /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; -@@ -1444,7 +1490,7 @@ int convert_to_git(struct index_state *istate, +@@ -1439,20 +1519,20 @@ int convert_to_git(struct index_state *istate, + if (!ret && ca.drv && ca.drv->required) + die(_("%s: clean filter '%s' failed"), path, ca.drv->name); + +- if (ret && dst) { ++ if (ret > 0 && dst) { + src = dst->buf; len = dst->len; } - ret |= encode_to_git(path, src, len, dst, ca.working_tree_encoding, conv_flags); +- if (ret && dst) { + ret |= encode_to_git(path, src, len, dst, ca.working_tree_encoding, ca.attr_action, conv_flags); - if (ret && dst) { ++ if (ret > 0 && dst) { src = dst->buf; len = dst->len; -@@ -1472,7 +1518,7 @@ void convert_to_git_filter_fd(struct index_state *istate, + } + + if (!(conv_flags & CONV_EOL_KEEP_CRLF)) { + ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags); +- if (ret && dst) { ++ if (ret > 0 && dst) { + src = dst->buf; + len = dst->len; + } +@@ -1472,7 +1552,7 @@ void convert_to_git_filter_fd(struct index_state *istate, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL)) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -146,16 +219,48 @@ index c7d6a85..f3db530 100644 crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags); ident_to_git(dst->buf, dst->len, dst, ca.ident); } -@@ -1504,7 +1550,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1487,7 +1567,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, + int ret = 0, ret_filter = 0; + + ret |= ident_to_worktree(src, len, dst, ca->ident); +- if (ret) { ++ if (ret > 0) { + src = dst->buf; + len = dst->len; + } +@@ -1498,16 +1578,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, + */ + if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) { + ret |= crlf_to_worktree(src, len, dst, ca->crlf_action); +- if (ret) { ++ if (ret > 0) { + 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->attr_action, ca->working_tree_encoding); - if (ret) { +- if (ret) { ++ int ret_encode = encode_to_worktree(path, src, len, dst, ca->attr_action, ca->working_tree_encoding); ++ if (ret_encode > 0) { ++ ret |= ret_encode; + src = dst->buf; + len = dst->len; ++ } else if (ret_encode < 0) { ++ ret = ret_encode; + } + + ret_filter = apply_filter( +@@ -1546,7 +1629,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, + convert_attrs(istate, &ca, path); + ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1, + NULL, NULL); +- if (ret) { ++ if (ret > 0) { src = dst->buf; len = dst->len; -@@ -2058,3 +2104,84 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) + } +@@ -2058,3 +2141,96 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) return CA_CLASS_STREAMABLE; } @@ -164,15 +269,25 @@ index c7d6a85..f3db530 100644 +#ifdef __MVS__ + +void tag_file_as_working_tree_encoding(struct index_state *istate, const char* path, int fd, int was_converted) { -+ struct conv_attrs ca; -+ convert_attrs(istate, &ca, path); ++ struct stat st; ++ if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) ++ return; ++ ++ if (was_converted < 0) { ++ __chgfdccsid(fd, utf8_ccsid); ++ __disableautocvt(fd); ++ return; ++ } ++ ++ struct conv_attrs ca; ++ convert_attrs(istate, &ca, path); + if (ca.attr_action != CRLF_BINARY) { + if (ca.working_tree_encoding) { -+ if (was_converted) + __chgfdcodeset(fd, ca.working_tree_encoding); + } -+ else ++ else { + __chgfdccsid(fd, utf8_ccsid); ++ } + } + else { + __setfdbinary(fd); diff --git a/stable-patches/copy.c.patch b/stable-patches/copy.c.patch index 431070e..b1ab27b 100644 --- a/stable-patches/copy.c.patch +++ b/stable-patches/copy.c.patch @@ -1,13 +1,15 @@ diff --git a/copy.c b/copy.c -index b668209..e0067b4 100644 +index b668209..846a9c1 100644 --- a/copy.c +++ b/copy.c -@@ -19,6 +19,9 @@ int copy_fd(int ifd, int ofd) +@@ -19,6 +19,11 @@ int copy_fd(int ifd, int ofd) if (write_in_full(ofd, buffer, len) < 0) return COPY_WRITE_ERROR; } +#ifdef __MVS__ -+ __copyfdccsid(ifd, ofd); ++ struct stat st; ++ if (fstat(ofd, &st) >= 0 && S_ISREG(st.st_mode)) ++ __copyfdccsid(ifd, ofd); +#endif return 0; } diff --git a/stable-patches/diff.c.patch b/stable-patches/diff.c.patch index 72b23fd..50ef6eb 100644 --- a/stable-patches/diff.c.patch +++ b/stable-patches/diff.c.patch @@ -1,5 +1,5 @@ diff --git a/diff.c b/diff.c -index a68ddd2..48ccc6b 100644 +index a68ddd2..3054b38 100644 --- a/diff.c +++ b/diff.c @@ -4194,6 +4194,7 @@ int diff_populate_filespec(struct repository *r, @@ -29,7 +29,16 @@ index a68ddd2..48ccc6b 100644 s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); s->should_munmap = 1; -@@ -4369,11 +4379,16 @@ static void prep_temp_blob(struct index_state *istate, +@@ -4277,7 +4287,7 @@ int diff_populate_filespec(struct repository *r, + /* + * Convert from working tree format to canonical git format + */ +- if (convert_to_git(r->index, s->path, s->data, s->size, &buf, conv_flags)) { ++ if (convert_to_git(r->index, s->path, s->data, s->size, &buf, conv_flags) > 0) { + size_t size = 0; + munmap(s->data, s->size); + s->should_munmap = 0; +@@ -4369,13 +4379,21 @@ static void prep_temp_blob(struct index_state *istate, temp->tempfile = mks_tempfile_dt("git-blob-XXXXXX", base); if (!temp->tempfile) die_errno("unable to create temp-file"); @@ -37,14 +46,21 @@ index a68ddd2..48ccc6b 100644 - (const char *)blob, (size_t)size, &buf, &meta)) { + int ret = convert_to_working_tree(istate, path, + (const char *)blob, (size_t)size, &buf, &meta); -+ if (ret) { ++ if (ret > 0) { blob = buf.buf; size = buf.len; } +- if (write_in_full(temp->tempfile->fd, blob, size) < 0 || +- close_tempfile_gently(temp->tempfile)) + ++ if (write_in_full(temp->tempfile->fd, blob, size) < 0) ++ die_errno("unable to write temp-file"); ++ +#ifdef __MVS__ + tag_file_as_working_tree_encoding(istate, path, temp->tempfile->fd, ret); +#endif - if (write_in_full(temp->tempfile->fd, blob, size) < 0 || - close_tempfile_gently(temp->tempfile)) ++ ++ if (close_tempfile_gently(temp->tempfile)) die_errno("unable to write temp-file"); + temp->name = get_tempfile_path(temp->tempfile); + oid_to_hex_r(temp->hex, oid); diff --git a/stable-patches/entry.c.patch b/stable-patches/entry.c.patch index a8c5d5a..bdd91bf 100644 --- a/stable-patches/entry.c.patch +++ b/stable-patches/entry.c.patch @@ -1,30 +1,100 @@ diff --git a/entry.c b/entry.c -index 7817aee..d2ca664 100644 +index 7817aee..54a93b6 100644 --- a/entry.c +++ b/entry.c -@@ -139,6 +139,10 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path, +@@ -85,8 +85,16 @@ static void remove_subtree(struct strbuf *path) + + static int create_file(const char *path, unsigned int mode) + { ++ int fd; + mode = (mode & 0100) ? 0777 : 0666; +- return open(path, O_WRONLY | O_CREAT | O_EXCL, mode); ++ fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); ++#ifdef __MVS__ ++ if (fd >= 0) { ++ __setfdbinary(fd); // Ensure raw binary write to prevent kernel interference ++ __disableautocvt(fd); ++ } ++#endif ++ return fd; + } + + void *read_blob_entry(const struct cache_entry *ce, size_t *size) +@@ -111,7 +119,14 @@ static int open_output_fd(char *path, const struct cache_entry *ce, int to_tempf + if (to_tempfile) { + xsnprintf(path, TEMPORARY_FILENAME_LENGTH, "%s", + symlink ? ".merge_link_XXXXXX" : ".merge_file_XXXXXX"); +- return mkstemp(path); ++ int fd = mkstemp(path); ++#ifdef __MVS__ ++ if (fd >= 0) { ++ __setfdbinary(fd); // Ensure raw binary write to prevent kernel interference ++ __disableautocvt(fd); ++ } ++#endif ++ return fd; + } else { + return create_file(path, !symlink ? ce->ce_mode : 0666); + } +@@ -139,7 +154,18 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path, if (fd < 0) return -1; +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(state->istate, path, fd, 1); ++ struct f_cnvrt query; ++ query.cvtcmd = QUERYCVT; ++ query.pccsid = 0; ++ query.fccsid = 0; ++ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); +#endif -+ result |= odb_stream_blob_to_fd(the_repository->objects, fd, &ce->oid, filter, 1); ++#ifdef __MVS__ ++ tag_file_as_working_tree_encoding(state->istate, (char*)ce->name, fd, result == 0 ? (filter ? 1 : 0) : -1); ++#endif *fstat_done = fstat_checkout_output(fd, state, statbuf); result |= close(fd); -@@ -385,6 +389,10 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca + +@@ -348,11 +374,18 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca + /* + * Convert from git internal format to working tree format + */ + if (dco && dco->state != CE_NO_DELAY) { + ret = async_convert_to_working_tree_ca(ca, ce->name, + new_blob, size, + &buf, &meta, dco); +- if (ret) { ++ if (ret > 0) { + struct string_list_item *item = + string_list_lookup(&dco->paths, ce->name); + if (item) { +@@ -367,7 +400,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca + size, &buf, &meta); + } + +- if (ret) { ++ if (ret > 0) { + free(new_blob); + new_blob = strbuf_detach(&buf, &newsize); + size = newsize; +@@ -385,7 +418,24 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca return error_errno("unable to create file %s", path); } +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(state->istate, path, fd, ret); ++ struct f_cnvrt query; ++ query.cvtcmd = QUERYCVT; ++ query.pccsid = 0; ++ query.fccsid = 0; ++ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); +#endif -+ wrote = write_in_full(fd, new_blob, size); ++#ifdef __MVS__ ++ tag_file_as_working_tree_encoding(state->istate, path, fd, ret); ++#endif if (!to_tempfile) fstat_done = fstat_checkout_output(fd, state, &st); -@@ -487,6 +495,25 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, + close(fd); +@@ -487,6 +537,25 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, struct stat st; struct conv_attrs ca_buf; diff --git a/stable-patches/hash-object.c.patch b/stable-patches/hash-object.c.patch index f6c6c6f..382225d 100644 --- a/stable-patches/hash-object.c.patch +++ b/stable-patches/hash-object.c.patch @@ -1,14 +1,18 @@ diff --git a/builtin/hash-object.c b/builtin/hash-object.c -index 5d900a6..35c46f8 100644 +index 5d900a6..5a5bfe8 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c -@@ -40,6 +40,10 @@ static void hash_object(const char *path, const char *type, const char *vpath, +@@ -40,6 +40,14 @@ static void hash_object(const char *path, const char *type, const char *vpath, { int fd; fd = xopen(path, O_RDONLY); +#ifdef __MVS__ -+ if (fd >= 0 && __setfdbinary(fd)) -+ die_errno("Cannot set to binary '%s'", path); ++ struct stat st; ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { ++ if (__setfdbinary(fd)) ++ die_errno("Cannot set to binary '%s'", path); ++ __disableautocvt(fd); ++ } +#endif hash_fd(fd, type, vpath, flags); } diff --git a/stable-patches/lockfile.c.patch b/stable-patches/lockfile.c.patch index 9fa7d3e..bd2bbb2 100644 --- a/stable-patches/lockfile.c.patch +++ b/stable-patches/lockfile.c.patch @@ -1,14 +1,15 @@ diff --git a/lockfile.c b/lockfile.c -index 67082a9..0944d14 100644 +index 67082a9..ed44413 100644 --- a/lockfile.c +++ b/lockfile.c -@@ -83,6 +83,10 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, +@@ -83,6 +83,11 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, strbuf_addstr(&filename, LOCK_SUFFIX); lk->tempfile = create_tempfile_mode(filename.buf, mode); +#ifdef __MVS__ -+ if (lk->tempfile) -+ __chgfdccsid(lk->tempfile->fd, 819); ++ struct stat st; ++ if (lk->tempfile && fstat(lk->tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) ++ __setfdbinary(lk->tempfile->fd); +#endif strbuf_release(&filename); return lk->tempfile ? lk->tempfile->fd : -1; diff --git a/stable-patches/object-file.c.patch b/stable-patches/object-file.c.patch index bbebd28..12a989f 100644 --- a/stable-patches/object-file.c.patch +++ b/stable-patches/object-file.c.patch @@ -1,30 +1,250 @@ diff --git a/object-file.c b/object-file.c -index e7e4c33..b08f7cd 100644 +index e7e4c33..b64b44b 100644 --- a/object-file.c +++ b/object-file.c -@@ -831,6 +831,10 @@ static int create_tmpfile(struct repository *repo, +@@ -154,7 +154,7 @@ int stream_object_signature(struct repository *r, const struct object_id *oid) + if (readlen < 0) { + odb_read_stream_close(st); + return -1; +- } ++ } + if (!readlen) + break; + git_hash_update(&c, buf, readlen); +@@ -225,7 +225,7 @@ static void *map_fd(int fd, const char *path, unsigned long *size) + error(_("object file %s is empty"), path); + close(fd); + return NULL; +- } ++ } + map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0); + } + close(fd); +@@ -329,7 +329,7 @@ static void *unpack_loose_rest(git_zstream *stream, + obj_read_unlock(); + status = git_inflate(stream, Z_FINISH); + obj_read_lock(); +- } ++ } + } + + if (status != Z_STREAM_END) { +@@ -393,7 +393,7 @@ static int parse_loose_header(const char *hdr, struct object_info *oi) + break; + hdr++; + size = st_add(st_mult(size, 10), c); +- } ++ } + } + + if (oi->sizep) +@@ -440,12 +440,12 @@ int odb_source_loose_read_object_info(struct odb_source *source, + if ((!oi || !oi->disk_sizep) && (flags & OBJECT_INFO_QUICK)) { + ret = quick_has_loose(source->loose, oid) ? 0 : -1; + goto out; +- } ++ } + + if (stat_loose_object(source->loose, oid, &st, &path) < 0) { + ret = -1; + goto out; +- } ++ } + + if (oi && oi->disk_sizep) + *oi->disk_sizep = st.st_size; +@@ -483,7 +483,7 @@ int odb_source_loose_read_object_info(struct odb_source *source, + if (parse_loose_header(hdr, oi) < 0) { + ret = error(_("unable to parse %s header"), oid_to_hex(oid)); + goto corrupt; +- } ++ } + + if (*oi->typep < 0) + die(_("invalid object type")); +@@ -493,8 +493,8 @@ int odb_source_loose_read_object_info(struct odb_source *source, + if (!*oi->contentp) { + ret = -1; + goto corrupt; +- } + } ++ } + + break; + case ULHR_BAD: +@@ -588,19 +588,19 @@ static int check_collision(const char *source, const char *dest) + if (sz_a < 0) { + ret = error_errno(_("unable to read %s"), source); + goto out; +- } ++ } + + sz_b = read_in_full(fd_dest, buf_dest, sizeof(buf_dest)); + if (sz_b < 0) { + ret = error_errno(_("unable to read %s"), dest); + goto out; +- } ++ } + + if (sz_a != sz_b || memcmp(buf_source, buf_dest, sz_a)) { + ret = error(_("files '%s' and '%s' differ in contents"), + source, dest); + goto out; +- } ++ } + + if ((size_t) sz_a < sizeof(buf_source)) + break; +@@ -668,7 +668,7 @@ int finalize_object_file_flags(struct repository *repo, + unlink_or_warn(tmpfile); + errno = saved_errno; + return error_errno(_("unable to write file %s"), filename); +- } ++ } + if (!(flags & FOF_SKIP_COLLISION_CHECK)) { + ret = check_collision(tmpfile, filename); + if (ret == CHECK_COLLISION_DEST_VANISHED) { +@@ -676,10 +676,10 @@ int finalize_object_file_flags(struct repository *repo, + return error(_("unable to write repeatedly vanishing file %s"), + filename); + goto retry; +- } ++ } + else if (ret) + return -1; +- } ++ } + unlink_or_warn(tmpfile); + } + +@@ -826,11 +826,20 @@ static int create_tmpfile(struct repository *repo, + struct strbuf *tmp, const char *filename) + { + int fd, dirlen = directory_size(filename); ++#ifdef __MVS__ ++ struct stat st; ++#endif + + strbuf_reset(tmp); strbuf_add(tmp, filename, dirlen); strbuf_addstr(tmp, "tmp_obj_XXXXXX"); fd = git_mkstemp_mode(tmp->buf, 0444); +#ifdef __MVS__ -+ if (fd >= 0) ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { + __setfdbinary(fd); ++ __disableautocvt(fd); ++ } +#endif if (fd < 0 && dirlen && errno == ENOENT) { /* * Make sure the directory exists; note that the contents -@@ -848,6 +852,10 @@ static int create_tmpfile(struct repository *repo, +@@ -848,6 +857,12 @@ static int create_tmpfile(struct repository *repo, /* Try again */ strbuf_addstr(tmp, "/tmp_obj_XXXXXX"); fd = git_mkstemp_mode(tmp->buf, 0444); +#ifdef __MVS__ -+ if (fd >= 0) ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { + __setfdbinary(fd); ++ __disableautocvt(fd); ++ } +#endif } return fd; } -@@ -1649,12 +1657,21 @@ int index_path(struct index_state *istate, struct object_id *oid, +@@ -1074,7 +1089,7 @@ int odb_source_loose_write_stream(struct odb_source *source, + /* All data has been read. */ + if (in_stream->is_finished) + flush = 1; +- } ++ } + ret = write_loose_object_common(source, &c, &compat_c, &stream, flush, in0, fd, + compressed, sizeof(compressed)); + /* +@@ -1120,7 +1135,7 @@ int odb_source_loose_write_stream(struct odb_source *source, + err = error_errno(_("unable to create directory %s"), dir.buf); + strbuf_release(&dir); + goto cleanup; +- } ++ } + strbuf_release(&dir); + } + +@@ -1158,7 +1173,7 @@ int odb_source_loose_write_object(struct odb_source *source, + hash_object_file(compat, converted.buf, converted.len, + type, &compat_oid); + strbuf_release(&converted); +- } ++ } + } + + /* Normally if we have it in the pack then we do not bother writing +@@ -1243,11 +1258,12 @@ static int index_mem(struct index_state *istate, + * Convert blobs to git internal format + */ + if ((type == OBJ_BLOB) && path) { +- if (convert_to_git(istate, path, buf, size, &nbuf, +- get_conv_flags(flags))) { ++ int ret = convert_to_git(istate, path, buf, size, &nbuf, ++ get_conv_flags(flags)); ++ if (ret > 0) { + buf = nbuf.buf; + size = nbuf.len; +- } ++ } + } + if (flags & INDEX_FORMAT_CHECK) { + struct fsck_options opts = FSCK_OPTIONS_DEFAULT; +@@ -1426,11 +1442,11 @@ static int stream_blob_to_pack(struct transaction_packfile *state, + if (hsize) + git_hash_update(ctx, ibuf, hsize); + *already_hashed_to = offset; +- } ++ } + s.next_in = ibuf; + s.avail_in = rsize; + size -= rsize; +- } ++ } + + status = git_deflate(&s, size ? 0 : Z_FINISH); + +@@ -1444,14 +1460,14 @@ static int stream_blob_to_pack(struct transaction_packfile *state, + pack_size_limit_cfg < state->offset + written) { + git_deflate_abort(&s); + return -1; +- } ++ } + + hashwrite(state->f, obuf, written); + state->offset += written; +- } ++ } + s.next_out = obuf; + s.avail_out = sizeof(obuf); +- } ++ } + + switch (status) { + case Z_OK: +@@ -1460,7 +1476,7 @@ static int stream_blob_to_pack(struct transaction_packfile *state, + continue; + default: + die("unexpected deflate failure: %d", status); +- } ++ } + } + git_deflate_end(&s); + return 0; +@@ -1572,7 +1588,7 @@ static int index_blob_packfile_transaction(struct odb_transaction *transaction, + hashfile_checkpoint(state->f, &checkpoint); + idx->offset = state->offset; + crc32_begin(state->f); +- } ++ } + if (!stream_blob_to_pack(state, &ctx, &already_hashed_to, + fd, size, path, flags)) + break; +@@ -1649,12 +1665,21 @@ int index_path(struct index_state *istate, struct object_id *oid, int fd; struct strbuf sb = STRBUF_INIT; int rc = 0; @@ -46,3 +266,46 @@ index e7e4c33..b08f7cd 100644 if (index_fd(istate, oid, fd, st, OBJ_BLOB, path, flags) < 0) return error(_("%s: failed to insert into database"), path); +@@ -1745,15 +1770,15 @@ static int for_each_file_in_obj_subdir(unsigned int subdir_nr, + r = obj_cb(&oid, path->buf, data); + if (r) + break; +- } +- continue; + } ++ continue; ++ } + + if (cruft_cb) { + r = cruft_cb(de->d_name, path->buf, data); + if (r) + break; +- } ++ } + } + closedir(dir); + +@@ -1967,7 +1992,7 @@ int read_loose_object(struct repository *repo, + if (!*contents) { + error(_("unable to unpack contents of %s"), path); + goto out_inflate; +- } ++ } + hash_object_file(repo->hash_algo, + *contents, *size, + *oi->typep, real_oid); +@@ -2082,12 +2107,12 @@ static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t + git_inflate_end(&st->z); + st->z_state = ODB_LOOSE_READ_STREAM_DONE; + break; +- } ++ } + if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) { + git_inflate_end(&st->z); + st->z_state = ODB_LOOSE_READ_STREAM_ERROR; + return -1; +- } ++ } + } + return total_read; + } diff --git a/stable-patches/odb.c.patch b/stable-patches/odb.c.patch index 06ef71c..825027f 100644 --- a/stable-patches/odb.c.patch +++ b/stable-patches/odb.c.patch @@ -1,29 +1,238 @@ diff --git a/odb.c b/odb.c -index ac70b6a..f43adf3 100644 +index ac70b6a..699e986 100644 --- a/odb.c +++ b/odb.c -@@ -76,6 +76,10 @@ int odb_mkstemp(struct object_database *odb, +@@ -66,9 +66,13 @@ static const struct cached_object *find_cached_object(struct object_database *ob + } + + int odb_mkstemp(struct object_database *odb, +- struct strbuf *temp_filename, const char *pattern) ++ struct strbuf *temp_filename, ++ const char *pattern) + { + int fd; ++#ifdef __MVS__ ++ struct stat st; ++#endif + /* + * we let the umask do its job, don't try to be more + * restrictive except to remove write permission. +@@ -76,6 +80,12 @@ int odb_mkstemp(struct object_database *odb, int mode = 0444; repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); fd = git_mkstemp_mode(temp_filename->buf, mode); +#ifdef __MVS__ -+ if (fd >= 0) ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { + __setfdbinary(fd); ++ __disableautocvt(fd); ++ } +#endif if (0 <= fd) return fd; -@@ -83,7 +87,12 @@ int odb_mkstemp(struct object_database *odb, +@@ -83,9 +93,17 @@ int odb_mkstemp(struct object_database *odb, /* some mkstemp implementations erase temp_filename on failure */ repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); safe_create_leading_directories(odb->repo, temp_filename->buf); - return xmkstemp_mode(temp_filename->buf, mode); + fd = xmkstemp_mode(temp_filename->buf, mode); +#ifdef __MVS__ -+ if (fd >= 0) ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { + __setfdbinary(fd); ++ __disableautocvt(fd); ++ } +#endif + return fd; } ++ /* + * Return non-zero iff the path is usable as an alternate object database. + */ +@@ -152,18 +170,18 @@ static void parse_alternates(const char *string, + if (*string == '#') { + /* comment; consume up to next separator */ + end = strchrnul(string, sep); +- } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { ++ } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { + /* + * quoted path; unquote_c_style has copied the + * data for us and set "end". Broken quoting (e.g., + * an entry that doesn't end with a quote) falls + * back to the unquoted case below. + */ +- } else { ++ } else { + /* normal, unquoted path */ + end = strchrnul(string, sep); + strbuf_add(&buf, string, end - string); +- } ++ } + + if (*end) + end++; +@@ -175,7 +193,7 @@ static void parse_alternates(const char *string, + if (!is_absolute_path(buf.buf) && relative_base) { + strbuf_realpath(&pathbuf, relative_base, 1); + strbuf_addch(&pathbuf, '/'); +- } ++ } + strbuf_addbuf(&pathbuf, &buf); + + strbuf_reset(&buf); +@@ -183,7 +201,7 @@ static void parse_alternates(const char *string, + error(_("unable to normalize alternate object path: %s"), + pathbuf.buf); + continue; +- } ++ } + + /* + * The trailing slash after the directory name is given by +@@ -296,9 +314,9 @@ static int odb_source_write_alternate(struct odb_source *source, + if (!strcmp(alternate, line.buf)) { + found = 1; + break; +- } +- fprintf_or_die(out, "%s\n", line.buf); + } ++ fprintf_or_die(out, "%s\n", line.buf); ++ } + + strbuf_release(&line); + fclose(in); +@@ -314,7 +332,7 @@ static int odb_source_write_alternate(struct odb_source *source, + if (commit_lock_file(&lock)) { + ret = error_errno(_("unable to move new alternates file into place")); + goto out; +- } ++ } + } + + ret = 0; +@@ -433,7 +451,7 @@ char *compute_alternate_path(const char *path, struct strbuf *err) + "checkout is not supported yet."), + path); + goto out; +- } ++ } + + strbuf_addf(err, _("reference repository '%s' is not a " + "local repository."), path); +@@ -517,7 +535,7 @@ static void fill_alternate_refs_command(struct repository *repo, + if (!repo_config_get_value(repo, "core.alternateRefsPrefixes", &value)) { + strvec_push(&cmd->args, "--"); + strvec_split(&cmd->args, value); +- } ++ } + } + + strvec_pushv(&cmd->env, (const char **)local_repo_env); +@@ -547,7 +565,7 @@ static void read_alternate_refs(struct repository *repo, + warning(_("invalid line while parsing alternate refs: %s"), + line.buf); + break; +- } ++ } + + cb(&oid, payload); + } +@@ -703,7 +721,7 @@ static int do_oid_object_info_extended(struct object_database *odb, + if (oi->contentp) + *oi->contentp = xmemdupz(co->buf, co->size); + oi->whence = OI_CACHED; +- } ++ } + return 0; + } + +@@ -717,7 +735,7 @@ static int do_oid_object_info_extended(struct object_database *odb, + if (!packfile_store_read_object_info(source->packfiles, real, oi, flags) || + !odb_source_loose_read_object_info(source, real, oi, flags)) + return 0; +- } ++ } + + /* Not a loose object; someone else may have just packed it. */ + if (!(flags & OBJECT_INFO_QUICK)) { +@@ -725,7 +743,7 @@ static int do_oid_object_info_extended(struct object_database *odb, + for (source = odb->sources; source; source = source->next) + if (!packfile_store_read_object_info(source->packfiles, real, oi, flags)) + return 0; +- } ++ } + + /* + * This might be an attempt at accessing a submodule object as +@@ -744,7 +762,7 @@ static int do_oid_object_info_extended(struct object_database *odb, + promisor_remote_get_direct(odb->repo, real, 1); + already_retried = 1; + continue; +- } ++ } + + if (flags & OBJECT_INFO_DIE_IF_CORRUPT) { + const struct packed_git *p; +@@ -754,7 +772,7 @@ static int do_oid_object_info_extended(struct object_database *odb, + if ((p = has_packed_and_bad(odb->repo, real))) + die(_("packed object %s (stored in %s) is corrupt"), + oid_to_hex(real), p->pack_name); +- } ++ } + return -1; + } + } +@@ -792,7 +810,7 @@ static int oid_object_info_convert(struct repository *r, + new_oi.contentp = &content; + new_oi.sizep = &size; + new_oi.typep = &type; +- } ++ } + oi = &new_oi; + } + +@@ -814,7 +832,7 @@ static int oid_object_info_convert(struct repository *r, + return -1; + size = outbuf.len; + content = strbuf_detach(&outbuf, NULL); +- } ++ } + if (input_oi->sizep) + *input_oi->sizep = size; + if (input_oi->contentp) +@@ -832,7 +850,7 @@ static int oid_object_info_convert(struct repository *r, + oid_to_hex(&delta_base_oid), + input_algo->name); + return -1; +- } ++ } + } + input_oi->whence = new_oi.whence; + input_oi->u = new_oi.u; +@@ -938,7 +956,7 @@ void *odb_read_object_peeled(struct object_database *odb, + if (actual_oid_return) + oidcpy(actual_oid_return, &actual_oid); + return buffer; +- } ++ } + /* Handle references */ + else if (type == OBJ_COMMIT) + ref_type = "tree "; +@@ -947,7 +965,7 @@ void *odb_read_object_peeled(struct object_database *odb, + else { + free(buffer); + return NULL; +- } ++ } + ref_length = strlen(ref_type); + + if (ref_length + odb->repo->hash_algo->hexsz > isize || +@@ -956,7 +974,7 @@ void *odb_read_object_peeled(struct object_database *odb, + odb->repo->hash_algo)) { + free(buffer); + return NULL; +- } ++ } + free(buffer); + /* Now we have the ID of the referred-to object in + * actual_oid. Check again. */ diff --git a/stable-patches/pack-write.c.patch b/stable-patches/pack-write.c.patch new file mode 100644 index 0000000..6020caa --- /dev/null +++ b/stable-patches/pack-write.c.patch @@ -0,0 +1,26 @@ +diff --git a/pack-write.c b/pack-write.c +index 83eaf88..510e2dc 100644 +--- a/pack-write.c ++++ b/pack-write.c +@@ -90,6 +90,10 @@ const char *write_idx_file(struct repository *repo, + } else { + unlink(index_name); + fd = xopen(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); ++#ifdef __MVS__ ++ __setfdbinary(fd); ++ __disableautocvt(fd); ++#endif + } + f = hashfd(repo->hash_algo, fd, index_name); + } +@@ -266,6 +270,10 @@ char *write_rev_file_order(struct repository *repo, + } else { + unlink(rev_name); + fd = xopen(rev_name, O_CREAT|O_EXCL|O_WRONLY, 0600); ++#ifdef __MVS__ ++ __setfdbinary(fd); ++ __disableautocvt(fd); ++#endif + path = xstrdup(rev_name); + } + f = hashfd(repo->hash_algo, fd, path); diff --git a/stable-patches/parallel-checkout.c.patch b/stable-patches/parallel-checkout.c.patch new file mode 100644 index 0000000..5046efd --- /dev/null +++ b/stable-patches/parallel-checkout.c.patch @@ -0,0 +1,46 @@ +diff --git a/parallel-checkout.c b/parallel-checkout.c +index 0bf4bd6..5aee95c 100644 +--- a/parallel-checkout.c ++++ b/parallel-checkout.c +@@ -3,6 +3,7 @@ + + #include "git-compat-util.h" + #include "config.h" ++#include "convert.h" + #include "entry.h" + #include "gettext.h" + #include "hash.h" +@@ -305,7 +306,7 @@ static int write_pc_item_to_fd(struct parallel_checkout_item *pc_item, int fd, + ret = convert_to_working_tree_ca(&pc_item->ca, pc_item->ce->name, + blob, size, &buf, NULL); + +- if (ret) { ++ if (ret > 0) { + size_t newsize; + free(blob); + blob = strbuf_detach(&buf, &newsize); +@@ -317,6 +318,10 @@ static int write_pc_item_to_fd(struct parallel_checkout_item *pc_item, int fd, + if (wrote < 0) + return error("unable to write file '%s'", path); + ++#ifdef __MVS__ ++ tag_file_as_working_tree_encoding(the_repository->index, path, fd, ret); ++#endif ++ + return 0; + } + +@@ -360,6 +365,13 @@ void write_pc_item(struct parallel_checkout_item *pc_item, + + fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, mode); + ++#ifdef __MVS__ ++ if (fd >= 0) { ++ __setfdbinary(fd); ++ __disableautocvt(fd); ++ } ++#endif ++ + if (fd < 0) { + if (errno == EEXIST || errno == EISDIR) { + /* diff --git a/stable-patches/repository.c.patch b/stable-patches/repository.c.patch index 5e0dace..75a2e70 100644 --- a/stable-patches/repository.c.patch +++ b/stable-patches/repository.c.patch @@ -1,8 +1,26 @@ diff --git a/repository.c b/repository.c -index c7e7521..11248ea 100644 +index c7e7521..c42709f 100644 --- a/repository.c +++ b/repository.c -@@ -446,7 +446,13 @@ int repo_hold_locked_index(struct repository *repo, +@@ -325,7 +325,7 @@ int repo_submodule_init(struct repository *subrepo, + if (!sub) { + ret = -1; + goto out; +- } ++ } + + strbuf_reset(&gitdir); + submodule_name_to_gitdir(&gitdir, superproject, sub->name); +@@ -333,7 +333,7 @@ int repo_submodule_init(struct repository *subrepo, + if (repo_init(subrepo, gitdir.buf, NULL)) { + ret = -1; + goto out; +- } ++ } + } + + subrepo->submodule_prefix = xstrfmt("%s%s/", +@@ -446,7 +446,16 @@ int repo_hold_locked_index(struct repository *repo, struct lock_file *lf, int flags) { @@ -12,8 +30,11 @@ index c7e7521..11248ea 100644 - return hold_lock_file_for_update(lf, repo->index_file, flags); + fd = hold_lock_file_for_update(lf, repo->index_file, flags); +#ifdef __MVS__ -+ if (fd >= 0) ++ struct stat st; ++ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { + __setfdbinary(fd); ++ __disableautocvt(fd); ++ } +#endif + return fd; } diff --git a/stable-patches/run-command.c.patch b/stable-patches/run-command.c.patch new file mode 100644 index 0000000..604eaca --- /dev/null +++ b/stable-patches/run-command.c.patch @@ -0,0 +1,86 @@ +diff --git a/run-command.c b/run-command.c +index e3e0247..ee3447b 100644 +--- a/run-command.c ++++ b/run-command.c +@@ -19,6 +19,10 @@ + #include "packfile.h" + #include "compat/nonblock.h" + ++#ifdef __MVS__ ++#include ++#endif ++ + void child_process_init(struct child_process *child) + { + struct child_process blank = CHILD_PROCESS_INIT; +@@ -695,6 +699,10 @@ int start_command(struct child_process *cmd) + str = "standard input"; + goto fail_pipe; + } ++#ifdef __MVS__ ++ __disableautocvt(fdin[0]); ++ __disableautocvt(fdin[1]); ++#endif + cmd->in = fdin[1]; + } + +@@ -711,6 +719,10 @@ int start_command(struct child_process *cmd) + str = "standard output"; + goto fail_pipe; + } ++#ifdef __MVS__ ++ __disableautocvt(fdout[0]); ++ __disableautocvt(fdout[1]); ++#endif + cmd->out = fdout[0]; + } + +@@ -727,13 +739,12 @@ int start_command(struct child_process *cmd) + else if (cmd->out) + close(cmd->out); + str = "standard error"; +-fail_pipe: +- error("cannot create %s pipe for %s: %s", +- str, cmd->args.v[0], strerror(failed_errno)); +- child_process_clear(cmd); +- errno = failed_errno; +- return -1; ++ goto fail_pipe; + } ++#ifdef __MVS__ ++ __disableautocvt(fderr[0]); ++ __disableautocvt(fderr[1]); ++#endif + cmd->err = fderr[0]; + } + +@@ -953,6 +964,7 @@ int start_command(struct child_process *cmd) + #endif + + if (cmd->pid < 0) { ++fail_pipe: + trace2_child_exit(cmd, -1); + + if (need_in) +@@ -1162,6 +1174,10 @@ int start_async(struct async *async) + close(async->out); + return error_errno("cannot create pipe"); + } ++#ifdef __MVS__ ++ __disableautocvt(fdin[0]); ++ __disableautocvt(fdin[1]); ++#endif + async->in = fdin[1]; + } + +@@ -1174,6 +1190,10 @@ int start_async(struct async *async) + close(async->in); + return error_errno("cannot create pipe"); + } ++#ifdef __MVS__ ++ __disableautocvt(fdout[0]); ++ __disableautocvt(fdout[1]); ++#endif + async->out = fdout[0]; + } + diff --git a/stable-patches/t-meson.build.patch b/stable-patches/t-meson.build.patch new file mode 100644 index 0000000..9c968a3 --- /dev/null +++ b/stable-patches/t-meson.build.patch @@ -0,0 +1,12 @@ +diff --git a/t/meson.build b/t/meson.build +index 459c52a..60c99db 100644 +--- a/t/meson.build ++++ b/t/meson.build +@@ -118,6 +118,7 @@ integration_tests = [ + 't0071-sort.sh', + 't0080-unit-test-output.sh', + 't0081-find-pack.sh', ++ 't0082-zos-encoding.sh', + 't0090-cache-tree.sh', + 't0091-bugreport.sh', + 't0092-diagnose.sh', diff --git a/stable-patches/t0082-zos-encoding.sh.patch b/stable-patches/t0082-zos-encoding.sh.patch new file mode 100644 index 0000000..a8361d0 --- /dev/null +++ b/stable-patches/t0082-zos-encoding.sh.patch @@ -0,0 +1,55 @@ +diff --git a/t/t0082-zos-encoding.sh b/t/t0082-zos-encoding.sh +new file mode 100755 +index 0000000..f0ec439 +--- /dev/null ++++ b/t/t0082-zos-encoding.sh +@@ -0,0 +1,49 @@ ++#!/bin/bash ++ ++test_description='z/OS encoding failure handling and tagging' ++ ++. ./test-lib.sh ++ ++# This test only makes sense on z/OS ++if ! uname | grep -q "OS/390"; then ++test_done ++fi ++ ++test_expect_success 'setup repo with character not in IBM-1047' ' ++git config core.ignorefiletags true && ++# C5 A7 is UTF-8 for ŧ. It does not exist in IBM-1047. ++printf "\xc5\xa7" >fail_blob.txt && ++git add fail_blob.txt && ++git commit -m "add utf8 blob" && ++ ++# Set the attribute. On checkout, it will try to convert UTF-8 -> IBM-1047 and fail. ++echo "fail_blob.txt working-tree-encoding=IBM-1047" >.gitattributes && ++git add .gitattributes && ++git commit -m "add attributes" && ++git config core.ignorefiletags false ++' ++ ++test_expect_success 'checkout fails encoding but tags as 1208' ' ++rm fail_blob.txt && ++# Use checkout-index -f to ensure we really try to write the file ++git checkout-index -f fail_blob.txt 2>err && ++grep "failed to encode" err && ++grep "line 1, col 1" err && ++grep "char: 0xc5" err && ++ ++# Verify the tag using chtag -p ++chtag -p fail_blob.txt >tag_info && ++grep "t UTF-8" tag_info && ++grep "T=on" tag_info && ++ ++# Verify content is still raw UTF-8 ++printf "\xc5\xa7" >expected && ++test_cmp expected fail_blob.txt ++' ++ ++test_expect_success 'git status remains clean after encoding failure' ' ++git status --porcelain -uno >status_out && ++test_must_be_empty status_out ++' ++ ++test_done From 4a84897db2e9f3b15c4d2b197165a6a8e81bcbf3 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Thu, 9 Apr 2026 00:04:12 -0400 Subject: [PATCH 03/12] Enabling tests for git, handled patch failure --- buildenv | 1 - stable-patches/config.mak.uname.patch | 8 +- stable-patches/convert.c.patch | 145 ++++++++++--------------- stable-patches/entry.c.patch | 65 ++++++----- stable-patches/git-compat-util.h.patch | 8 +- stable-patches/strbuf.c.patch | 0 stable-patches/utf8.c.patch | 60 +++++----- stable-patches/utf8.h.patch | 15 +++ 8 files changed, 143 insertions(+), 159 deletions(-) create mode 100644 stable-patches/strbuf.c.patch create mode 100644 stable-patches/utf8.h.patch diff --git a/buildenv b/buildenv index 0f07f6d..1619697 100644 --- a/buildenv +++ b/buildenv @@ -1,7 +1,6 @@ # export ZOPEN_BUILD_LINE="STABLE" export ZOPEN_CATEGORIES="development source_control" -export PERL_HOME="/home/haritha/zopen_23may/zopen/usr/local/zopen/perl/perl" # bump: git-version /GIT_VERSION="(.*)"/ https://github.com/git/git.git|* GIT_VERSION="2.53.0" diff --git a/stable-patches/config.mak.uname.patch b/stable-patches/config.mak.uname.patch index fcf69b9..6d88424 100644 --- a/stable-patches/config.mak.uname.patch +++ b/stable-patches/config.mak.uname.patch @@ -1,12 +1,12 @@ diff --git a/config.mak.uname b/config.mak.uname -index d5112168a4..17716314c0 100644 +index 3c35ae3..bda092f 100644 --- a/config.mak.uname +++ b/config.mak.uname -@@ -639,12 +639,21 @@ ifeq ($(uname_S),NONSTOP_KERNEL) +@@ -653,15 +653,24 @@ ifeq ($(uname_S),NONSTOP_KERNEL) SHELL_PATH = /usr/coreutils/bin/bash endif ifeq ($(uname_S),OS/390) -+ PERL_PATH = $(PERL_HOME)/bin/perl ++ PERL_PATH = $(PERL5_HOME)/bin/perl + PERL_PATH_FOR_SCRIPTS = /bin/env perl + SHELL_PATH = $(BASH_HOME)/bin/bash + SHELL_PATH_FOR_SCRIPTS = /bin/env bash @@ -24,4 +24,6 @@ index d5112168a4..17716314c0 100644 HAVE_STRINGS_H = YesPlease + NEEDS_LIBICONV = YesPlease + ICONVDIR = $(LIBICONV_HOME) + NEEDS_MODE_TRANSLATION = YesPlease + HAVE_ZOS_GET_EXECUTABLE_PATH = YesPlease endif diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index f321680..83fab2e 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -1,5 +1,5 @@ diff --git a/convert.c b/convert.c -index c7d6a85..1c49d9f 100644 +index c7d6a85..56b806b 100644 --- a/convert.c +++ b/convert.c @@ -6,6 +6,7 @@ @@ -21,12 +21,12 @@ index c7d6a85..1c49d9f 100644 /* * convert.c - convert a file when checking it out and checking it in. -@@ -385,12 +390,16 @@ static int check_roundtrip(const char *enc_name) +@@ -385,12 +390,17 @@ static int check_roundtrip(const char *enc_name) static const char *default_encoding = "UTF-8"; static int encode_to_git(const char *path, const char *src, size_t src_len, - struct strbuf *buf, const char *enc, int conv_flags) -+ struct strbuf *buf, const char *enc, ++ struct strbuf *buf, const char *enc, + enum convert_crlf_action attr_action, int conv_flags) { char *dst; @@ -36,46 +36,34 @@ index c7d6a85..1c49d9f 100644 + if (attr_action == CRLF_BINARY) { + return 0; + } ++ /* * No encoding is specified or there is nothing to encode. * Tell the caller that the content was not modified. -@@ -411,6 +420,12 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -411,6 +421,12 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, return 0; trace_encoding("source", path, enc, src, src_len); -+#ifdef __MVS__ -+ // If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files -+ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) -+ return 0; -+#endif + ++ #ifdef __MVS__ ++ // If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files ++ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) ++ return 0; ++ #endif dst = reencode_string_len(src, src_len, default_encoding, enc, &dst_len); if (!dst) { -@@ -420,12 +435,32 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -420,12 +436,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, * would fail and we would leave the user with a messed-up * working tree. Let's try to avoid this by screaming loud. */ - const char* msg = _("failed to encode '%s' from %s to %s"); -+ if (attr_action == CRLF_BINARY) { ++ if (attr_action == CRLF_BINARY) { + return 0; + } -+ size_t line = 1; -+ size_t col = 1; -+ unsigned char bad_char = 0; -+ for (size_t i = 0; i < src_len; i++) { -+ if (src[i] == '\n') { -+ line++; -+ col = 1; -+ } else { -+ col++; -+ } -+ /* Try to find the first character that iconv would reject */ -+ if ((unsigned char)src[i] > 0x7F) { -+ bad_char = (unsigned char)src[i]; -+ break; -+ } -+ } ++ size_t line, col; ++ unsigned char bad_char; ++ find_first_non_ascii(src, src_len, &line, &col, &bad_char); + + const char* msg = _("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"); if (die_on_error) @@ -89,7 +77,7 @@ index c7d6a85..1c49d9f 100644 } } trace_encoding("destination", path, default_encoding, dst, dst_len); -@@ -476,10 +511,14 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -476,10 +499,14 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, } static int encode_to_worktree(const char *path, const char *src, size_t src_len, @@ -99,43 +87,29 @@ index c7d6a85..1c49d9f 100644 { char *dst; size_t dst_len; -+if (attr_action == CRLF_BINARY) { -+ return 0; -+} ++ if (attr_action == CRLF_BINARY) { ++ return 0; ++ } /* * No encoding is specified or there is nothing to encode. -@@ -491,9 +530,26 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len, +@@ -491,9 +518,12 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len, dst = reencode_string_len(src, src_len, enc, default_encoding, &dst_len); if (!dst) { - error(_("failed to encode '%s' from %s to %s"), - path, default_encoding, enc); - return 0; -+ size_t line = 1; -+ size_t col = 1; -+ unsigned char bad_char = 0; -+ for (size_t i = 0; i < src_len; i++) { -+ if (src[i] == '\n') { -+ line++; -+ col = 1; -+ } else { -+ col++; -+ } -+ /* Try to find the first character that iconv would reject for IBM-1047 */ -+ /* (In a real implementation, we could call iconv in a loop here) */ -+ if ((unsigned char)src[i] > 0x7F) { -+ bad_char = (unsigned char)src[i]; -+ break; -+ } -+ } ++ size_t line, col; ++ unsigned char bad_char; ++ find_first_non_ascii(src, src_len, &line, &col, &bad_char); + error(_("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"), + path, default_encoding, enc, line, col, bad_char); + return -1; } strbuf_attach(buf, dst, dst_len, dst_len + 1); -@@ -1316,18 +1372,40 @@ static int git_path_check_ident(struct attr_check_item *check) +@@ -1316,18 +1346,40 @@ static int git_path_check_ident(struct attr_check_item *check) static struct attr_check *check; @@ -152,7 +126,7 @@ index c7d6a85..1c49d9f 100644 + /* Map OS/390 to 'zos' for platform-specific encoding attributes */ + if (!strcmp(uname_info.sysname, "OS/390")) + return "zos"; -+ ++ + xsnprintf(platform_name, sizeof(platform_name), "%s", uname_info.sysname); + return platform_name; +} @@ -176,16 +150,17 @@ index c7d6a85..1c49d9f 100644 git_check_attr(istate, path, check); ccheck = check->items; -@@ -1348,6 +1426,8 @@ void convert_attrs(struct index_state *istate, +@@ -1348,6 +1400,9 @@ void convert_attrs(struct index_state *istate, ca->crlf_action = CRLF_TEXT_CRLF; } ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); + if (git_path_check_encoding(ccheck + 6)) -+ ca->working_tree_encoding = git_path_check_encoding(ccheck + 6); ++ ca->working_tree_encoding = git_path_check_encoding(ccheck + 6); ++ /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; -@@ -1439,20 +1519,20 @@ int convert_to_git(struct index_state *istate, +@@ -1439,13 +1494,13 @@ int convert_to_git(struct index_state *istate, if (!ret && ca.drv && ca.drv->required) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -202,15 +177,7 @@ index c7d6a85..1c49d9f 100644 src = dst->buf; len = dst->len; } - - if (!(conv_flags & CONV_EOL_KEEP_CRLF)) { - ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags); -- if (ret && dst) { -+ if (ret > 0 && dst) { - src = dst->buf; - len = dst->len; - } -@@ -1472,7 +1552,7 @@ void convert_to_git_filter_fd(struct index_state *istate, +@@ -1472,7 +1527,7 @@ void convert_to_git_filter_fd(struct index_state *istate, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL)) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -219,7 +186,7 @@ index c7d6a85..1c49d9f 100644 crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags); ident_to_git(dst->buf, dst->len, dst, ca.ident); } -@@ -1487,7 +1567,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1487,7 +1542,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, int ret = 0, ret_filter = 0; ret |= ident_to_worktree(src, len, dst, ca->ident); @@ -228,7 +195,7 @@ index c7d6a85..1c49d9f 100644 src = dst->buf; len = dst->len; } -@@ -1498,16 +1578,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1498,16 +1553,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, */ if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) { ret |= crlf_to_worktree(src, len, dst, ca->crlf_action); @@ -251,7 +218,7 @@ index c7d6a85..1c49d9f 100644 } ret_filter = apply_filter( -@@ -1546,7 +1629,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, +@@ -1546,7 +1604,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, convert_attrs(istate, &ca, path); ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1, NULL, NULL); @@ -260,7 +227,7 @@ index c7d6a85..1c49d9f 100644 src = dst->buf; len = dst->len; } -@@ -2058,3 +2141,96 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) +@@ -2058,3 +2116,96 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) return CA_CLASS_STREAMABLE; } @@ -269,31 +236,31 @@ index c7d6a85..1c49d9f 100644 +#ifdef __MVS__ + +void tag_file_as_working_tree_encoding(struct index_state *istate, const char* path, int fd, int was_converted) { -+ struct stat st; -+ if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) -+ return; ++ struct stat st; ++ if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) ++ return; + -+ if (was_converted < 0) { -+ __chgfdccsid(fd, utf8_ccsid); -+ __disableautocvt(fd); -+ return; -+ } ++ if (was_converted < 0) { ++ __chgfdccsid(fd, 1208); ++ __disableautocvt(fd); ++ return; ++ } + -+ struct conv_attrs ca; -+ convert_attrs(istate, &ca, path); -+ if (ca.attr_action != CRLF_BINARY) { -+ if (ca.working_tree_encoding) { -+ __chgfdcodeset(fd, ca.working_tree_encoding); -+ } -+ else { -+ __chgfdccsid(fd, utf8_ccsid); -+ } -+ } -+ else { -+ __setfdbinary(fd); -+ } ++ struct conv_attrs ca; ++ convert_attrs(istate, &ca, path); ++ if (ca.attr_action != CRLF_BINARY) { ++ if (ca.working_tree_encoding) { ++ __chgfdcodeset(fd, ca.working_tree_encoding); ++ } ++ else { ++ __chgfdccsid(fd, utf8_ccsid); ++ } ++ } ++ else { ++ __setfdbinary(fd); ++ } + -+ __disableautocvt(fd); ++ __disableautocvt(fd); +} + +void validate_codeset(struct index_state *istate, const char *path, int* autoconvertToASCII) { diff --git a/stable-patches/entry.c.patch b/stable-patches/entry.c.patch index bdd91bf..3664609 100644 --- a/stable-patches/entry.c.patch +++ b/stable-patches/entry.c.patch @@ -1,22 +1,23 @@ diff --git a/entry.c b/entry.c -index 7817aee..54a93b6 100644 +index 7817aee362..e977570d5c 100644 --- a/entry.c +++ b/entry.c @@ -85,8 +85,16 @@ static void remove_subtree(struct strbuf *path) static int create_file(const char *path, unsigned int mode) { -+ int fd; - mode = (mode & 0100) ? 0777 : 0666; +- mode = (mode & 0100) ? 0777 : 0666; - return open(path, O_WRONLY | O_CREAT | O_EXCL, mode); -+ fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); ++ int fd; ++ mode = (mode & 0100) ? 0777 : 0666; ++ fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); +#ifdef __MVS__ -+ if (fd >= 0) { ++ if (fd >= 0) { + __setfdbinary(fd); // Ensure raw binary write to prevent kernel interference + __disableautocvt(fd); -+ } ++ } +#endif -+ return fd; ++ return fd; } void *read_blob_entry(const struct cache_entry *ce, size_t *size) @@ -41,24 +42,21 @@ index 7817aee..54a93b6 100644 return -1; +#ifdef __MVS__ -+ struct f_cnvrt query; -+ query.cvtcmd = QUERYCVT; -+ query.pccsid = 0; -+ query.fccsid = 0; -+ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); ++ struct f_cnvrt query; ++ query.cvtcmd = QUERYCVT; ++ query.pccsid = 0; ++ query.fccsid = 0; ++ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); +#endif result |= odb_stream_blob_to_fd(the_repository->objects, fd, &ce->oid, filter, 1); +#ifdef __MVS__ -+ tag_file_as_working_tree_encoding(state->istate, (char*)ce->name, fd, result == 0 ? (filter ? 1 : 0) : -1); ++ tag_file_as_working_tree_encoding(state->istate, (char*)ce->name, fd, result == 0 ? (filter ? 1 : 0) : -1); +#endif ++ *fstat_done = fstat_checkout_output(fd, state, statbuf); result |= close(fd); -@@ -348,11 +374,18 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca - /* - * Convert from git internal format to working tree format - */ - if (dco && dco->state != CE_NO_DELAY) { +@@ -352,7 +378,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca ret = async_convert_to_working_tree_ca(ca, ce->name, new_blob, size, &buf, &meta, dco); @@ -67,7 +65,7 @@ index 7817aee..54a93b6 100644 struct string_list_item *item = string_list_lookup(&dco->paths, ce->name); if (item) { -@@ -367,7 +400,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca +@@ -367,7 +393,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca size, &buf, &meta); } @@ -76,16 +74,17 @@ index 7817aee..54a93b6 100644 free(new_blob); new_blob = strbuf_detach(&buf, &newsize); size = newsize; -@@ -385,7 +418,24 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca +@@ -384,8 +410,17 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca + free(new_blob); return error_errno("unable to create file %s", path); } - +- +#ifdef __MVS__ -+ struct f_cnvrt query; -+ query.cvtcmd = QUERYCVT; -+ query.pccsid = 0; -+ query.fccsid = 0; -+ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); ++ struct f_cnvrt query; ++ query.cvtcmd = QUERYCVT; ++ query.pccsid = 0; ++ query.fccsid = 0; ++ int fcntl_ret = fcntl(fd, F_CONTROL_CVT, &query); +#endif wrote = write_in_full(fd, new_blob, size); +#ifdef __MVS__ @@ -94,11 +93,10 @@ index 7817aee..54a93b6 100644 if (!to_tempfile) fstat_done = fstat_checkout_output(fd, state, &st); close(fd); -@@ -487,6 +537,25 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, +@@ -486,6 +521,23 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, + static struct strbuf path = STRBUF_INIT; struct stat st; struct conv_attrs ca_buf; - -+ +#ifdef __MVS__ + const char* git_utf8_ccsid_str = getenv("GIT_UTF8_CCSID"); + @@ -108,15 +106,14 @@ index 7817aee..54a93b6 100644 + long conv = strtol(git_utf8_ccsid_str, &endptr, 10); + + if (!conv) { -+ perror("Error converting GIT_UTF8_CCSID to short"); ++ perror("Error converting GIT_UTF8_CCSID to short"); + } else if (endptr == git_utf8_ccsid_str) { -+ fprintf(stderr, "No digits were found in GIT_UTF8_CCSID\n"); ++ fprintf(stderr, "No digits were found in GIT_UTF8_CCSID\n"); + } else { -+ utf8_ccsid = conv; ++ utf8_ccsid = conv; + } + } +#endif -+ + if (ce->ce_flags & CE_WT_REMOVE) { if (topath) - /* diff --git a/stable-patches/git-compat-util.h.patch b/stable-patches/git-compat-util.h.patch index 21b2dbe..73704ff 100644 --- a/stable-patches/git-compat-util.h.patch +++ b/stable-patches/git-compat-util.h.patch @@ -1,13 +1,17 @@ diff --git a/git-compat-util.h b/git-compat-util.h -index bebcf9f..eca558e 100644 +index bebcf9f..74776ff 100644 --- a/git-compat-util.h +++ b/git-compat-util.h -@@ -371,6 +371,10 @@ static inline int git_has_dir_sep(const char *path) +@@ -371,6 +371,14 @@ static inline int git_has_dir_sep(const char *path) #endif #endif +#ifdef __MVS__ +#include ++/* Identify EBCDIC NL (0x15) which is distinct from ASCII LF (0x0A) */ ++#define is_ebcdic_newline(ch) ((unsigned char)(ch) == 0x15) ++#else ++#define is_ebcdic_newline(ch) 0 +#endif + #if defined(__HP_cc) && (__HP_cc >= 61000) diff --git a/stable-patches/strbuf.c.patch b/stable-patches/strbuf.c.patch new file mode 100644 index 0000000..e69de29 diff --git a/stable-patches/utf8.c.patch b/stable-patches/utf8.c.patch index 420dd49..6dbbe90 100644 --- a/stable-patches/utf8.c.patch +++ b/stable-patches/utf8.c.patch @@ -1,35 +1,35 @@ diff --git a/utf8.c b/utf8.c -index 96460cc..7f7985c 100644 +index 96460cc..5ab0f89 100644 --- a/utf8.c +++ b/utf8.c -@@ -3,6 +3,9 @@ - #include "git-compat-util.h" - #include "strbuf.h" - #include "utf8.h" -+#ifdef __MVS__ -+extern int utf8_ccsid; -+#endif +@@ -817,6 +817,30 @@ int skip_utf8_bom(char **text, size_t len) + return 1; + } - /* This code is originally from https://www.cl.cam.ac.uk/~mgk25/ucs/ */ - -@@ -605,6 +608,20 @@ char *reencode_string_len(const char *in, size_t insz, - #endif - } - -+#ifdef __MVS__ -+ if (utf8_ccsid == 819) { -+ //HACK: For backwards compat UTF CCSID=819, ISO8859-1 really means utf-8 in the z/OS world -+ if (strcasecmp("ISO8859-1", in_encoding) == 0) { -+ in_encoding = "UTF-8"; -+ out_encoding = "UTF-8"; -+ } -+ if (strcasecmp("ISO8859-1", out_encoding) == 0) { -+ in_encoding = "UTF-8"; -+ out_encoding = "UTF-8"; -+ } -+ } -+#endif ++void find_first_non_ascii(const char *src, size_t src_len, ++ size_t *line_out, size_t *col_out, ++ unsigned char *bad_char_out) ++{ ++ size_t line = 1, col = 1; ++ unsigned char bad_char = 0; ++ for (size_t i = 0; i < src_len; i++) { ++ if (src[i] == '\n' || is_ebcdic_newline(src[i])) { ++ line++; ++ col = 1; ++ } else { ++ col++; ++ } ++ /* Try to find the first character that iconv would reject (non-ASCII) */ ++ if ((unsigned char)src[i] > 0x7F) { ++ bad_char = (unsigned char)src[i]; ++ break; ++ } ++ } ++ *line_out = line; ++ *col_out = col; ++ *bad_char_out = bad_char; ++} + - conv = iconv_open(out_encoding, in_encoding); - if (conv == (iconv_t) -1) { - in_encoding = fallback_encoding(in_encoding); + void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width, + const char *s) + { diff --git a/stable-patches/utf8.h.patch b/stable-patches/utf8.h.patch new file mode 100644 index 0000000..bb0f64d --- /dev/null +++ b/stable-patches/utf8.h.patch @@ -0,0 +1,15 @@ +diff --git a/utf8.h b/utf8.h +index cf8ecb0..d80d85a 100644 +--- a/utf8.h ++++ b/utf8.h +@@ -50,6 +50,10 @@ static inline char *reencode_string(const char *in, + + int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding); + ++void find_first_non_ascii(const char *src, size_t src_len, ++ size_t *line_out, size_t *col_out, ++ unsigned char *bad_char_out); ++ + /* + * Returns true if the path would match ".git" after HFS case-folding. + * The path should be NUL-terminated, but we will match variants of both ".git\0" From dd6e4b46e0e796b6fb23cec1051f360f589b2d40 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Mon, 13 Apr 2026 01:17:56 -0400 Subject: [PATCH 04/12] Enabled all tests --- buildenv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildenv b/buildenv index 1619697..c8e242c 100644 --- a/buildenv +++ b/buildenv @@ -27,7 +27,7 @@ export ZOPEN_MAKE_OPTS="" export ZOPEN_INSTALL="zopen_install_all" export ZOPEN_INSTALL_OPTS="" #export ZOPEN_CHECK_OPTS="-i test -j\$ZOPEN_NUM_JOBS" -export ZOPEN_CHECK_OPTS="test -j\$ZOPEN_NUM_JOBS" +export ZOPEN_CHECK_OPTS="-i test -j\$ZOPEN_NUM_JOBS" export ZOPEN_COMP=CLANG export ZOPEN_EXTRA_CONFIGURE_OPTS="--with-zlib=\${ZLIB_HOME} --with-curl=\${CURL_HOME} --with-openssl=\${OPENSSL_HOME} --with-libpcre2=\${PCRE2_HOME} --with-libiconv-prefix=\${LIBICONV_HOME}" From 1bb4dd20e0e62e0a1a6036959bf86bf21a57d33a Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Mon, 13 Apr 2026 01:18:48 -0400 Subject: [PATCH 05/12] Enabled all tests --- stable-patches/common-init.c.patch | 35 ++++++ stable-patches/config.mak.uname.patch | 5 +- stable-patches/convert.c.patch | 146 +++++++++++++++++++++++--- stable-patches/entry.c.patch | 26 +---- 4 files changed, 169 insertions(+), 43 deletions(-) diff --git a/stable-patches/common-init.c.patch b/stable-patches/common-init.c.patch index e69de29..08f9a3e 100644 --- a/stable-patches/common-init.c.patch +++ b/stable-patches/common-init.c.patch @@ -0,0 +1,35 @@ +diff --git a/common-init.c b/common-init.c +index 5cc73f0..fe79089 100644 +--- a/common-init.c ++++ b/common-init.c +@@ -9,6 +9,9 @@ + #include "setup.h" + #include "strbuf.h" + #include "trace2.h" ++#ifdef __MVS__ ++#include "environment.h" ++#endif + + /* + * Many parts of Git have subprograms communicate via pipe, expect the +@@ -37,6 +40,20 @@ void init_git(const char **argv) + + trace2_initialize_clock(); + ++#ifdef __MVS__ ++ const char* git_utf8_ccsid_str = getenv("GIT_UTF8_CCSID"); ++ ++ if (git_utf8_ccsid_str != NULL) { ++ char* endptr; ++ errno = 0; ++ long conv = strtol(git_utf8_ccsid_str, &endptr, 10); ++ ++ if (conv > 0 && endptr != git_utf8_ccsid_str) { ++ utf8_ccsid = (int)conv; ++ } ++ } ++#endif ++ + /* + * Always open file descriptors 0/1/2 to avoid clobbering files + * in die(). It also avoids messing up when the pipes are dup'ed diff --git a/stable-patches/config.mak.uname.patch b/stable-patches/config.mak.uname.patch index 6d88424..1116d31 100644 --- a/stable-patches/config.mak.uname.patch +++ b/stable-patches/config.mak.uname.patch @@ -1,14 +1,15 @@ diff --git a/config.mak.uname b/config.mak.uname -index 3c35ae3..bda092f 100644 +index 3c35ae3..d9aba56 100644 --- a/config.mak.uname +++ b/config.mak.uname -@@ -653,15 +653,24 @@ ifeq ($(uname_S),NONSTOP_KERNEL) +@@ -653,15 +653,25 @@ ifeq ($(uname_S),NONSTOP_KERNEL) SHELL_PATH = /usr/coreutils/bin/bash endif ifeq ($(uname_S),OS/390) + PERL_PATH = $(PERL5_HOME)/bin/perl + PERL_PATH_FOR_SCRIPTS = /bin/env perl + SHELL_PATH = $(BASH_HOME)/bin/bash ++ TEST_SHELL_PATH = $(SHELL_PATH) + SHELL_PATH_FOR_SCRIPTS = /bin/env bash + PYTHON_PATH = /home/opnzos/local/pyz/bin/python NO_SYS_POLL_H = YesPlease diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index 83fab2e..f15f575 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -1,5 +1,5 @@ diff --git a/convert.c b/convert.c -index c7d6a85..56b806b 100644 +index c7d6a85..c57c165 100644 --- a/convert.c +++ b/convert.c @@ -6,6 +6,7 @@ @@ -21,7 +21,40 @@ index c7d6a85..56b806b 100644 /* * convert.c - convert a file when checking it out and checking it in. -@@ -385,12 +390,17 @@ static int check_roundtrip(const char *enc_name) +@@ -51,14 +56,14 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * + for (i = 0; i < size; i++) { + unsigned char c = buf[i]; + if (c == '\r') { +- if (i+1 < size && buf[i+1] == '\n') { ++ if (i+1 < size && (buf[i+1] == '\n' || is_ebcdic_newline(buf[i+1]))) { + stats->crlf++; + i++; + } else + stats->lonecr++; + continue; + } +- if (c == '\n') { ++ if (c == '\n' || is_ebcdic_newline(c)) { + stats->lonelf++; + continue; + } +@@ -87,6 +92,15 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * + stats->nonprintable--; + } + ++static const char *find_next_newline(const char *src, unsigned long len) ++{ ++ for (unsigned long i = 0; i < len; i++) { ++ if (src[i] == '\n' || is_ebcdic_newline(src[i])) ++ return src + i; ++ } ++ return NULL; ++} ++ + /* + * The same heuristics as diff.c::mmfile_is_binary() + * We treat files with bare CR as binary +@@ -385,17 +399,22 @@ static int check_roundtrip(const char *enc_name) static const char *default_encoding = "UTF-8"; static int encode_to_git(const char *path, const char *src, size_t src_len, @@ -40,7 +73,13 @@ index c7d6a85..56b806b 100644 /* * No encoding is specified or there is nothing to encode. * Tell the caller that the content was not modified. -@@ -411,6 +421,12 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, + */ +- if (!enc || (src && !src_len)) ++ if (!enc || same_encoding(enc, default_encoding) || (src && !src_len)) + return 0; + + /* +@@ -411,8 +430,18 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, return 0; trace_encoding("source", path, enc, src, src_len); @@ -52,8 +91,14 @@ index c7d6a85..56b806b 100644 + #endif dst = reencode_string_len(src, src_len, default_encoding, enc, &dst_len); ++ if (!dst) { ++ dst = reencode_string_len_translit(src, src_len, default_encoding, enc, ++ &dst_len); ++ } if (!dst) { -@@ -420,12 +436,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, + /* + * We could add the blob "as-is" to Git. However, on checkout +@@ -420,12 +449,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, * would fail and we would leave the user with a messed-up * working tree. Let's try to avoid this by screaming loud. */ @@ -77,7 +122,7 @@ index c7d6a85..56b806b 100644 } } trace_encoding("destination", path, default_encoding, dst, dst_len); -@@ -476,10 +499,14 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -476,24 +512,40 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, } static int encode_to_worktree(const char *path, const char *src, size_t src_len, @@ -93,13 +138,27 @@ index c7d6a85..56b806b 100644 /* * No encoding is specified or there is nothing to encode. -@@ -491,9 +518,12 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len, + * Tell the caller that the content was not modified. + */ +- if (!enc || (src && !src_len)) ++ if (!enc || same_encoding(enc, default_encoding) || (src && !src_len)) + return 0; + ++ #ifdef __MVS__ ++ // If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files ++ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) ++ return 0; ++ #endif dst = reencode_string_len(src, src_len, enc, default_encoding, &dst_len); if (!dst) { - error(_("failed to encode '%s' from %s to %s"), - path, default_encoding, enc); - return 0; ++ dst = reencode_string_len_translit(src, src_len, enc, default_encoding, ++ &dst_len); ++ } ++ if (!dst) { + size_t line, col; + unsigned char bad_char; + find_first_non_ascii(src, src_len, &line, &col, &bad_char); @@ -109,7 +168,51 @@ index c7d6a85..56b806b 100644 } strbuf_attach(buf, dst, dst_len, dst_len + 1); -@@ -1316,18 +1346,40 @@ static int git_path_check_ident(struct attr_check_item *check) +@@ -581,7 +633,7 @@ static int crlf_to_git(struct index_state *istate, + } else { + do { + unsigned char c = *src++; +- if (! (c == '\r' && (1 < len && *src == '\n'))) ++ if (! (c == '\r' && (1 < len && (*src == '\n' || is_ebcdic_newline(*src))))) + *dst++ = c; + } while (--len); + } +@@ -608,14 +660,17 @@ static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf, + + strbuf_grow(buf, len + stats.lonelf); + for (;;) { +- const char *nl = memchr(src, '\n', len); ++ const char *nl = find_next_newline(src, len); + if (!nl) + break; + if (nl > src && nl[-1] == '\r') { + strbuf_add(buf, src, nl + 1 - src); + } else { + strbuf_add(buf, src, nl - src); +- strbuf_addstr(buf, "\r\n"); ++ if (is_ebcdic_newline(*nl)) ++ strbuf_addstr(buf, "\r\x15"); ++ else ++ strbuf_addstr(buf, "\r\n"); + } + len -= nl + 1 - src; + src = nl + 1; +@@ -1257,13 +1312,10 @@ static const char *git_path_check_encoding(struct attr_check_item *check) + die(_("true/false are no valid working-tree-encodings")); + } + +- /* Don't encode to the default encoding */ +- if (same_encoding(value, default_encoding)) +- return NULL; +- + return value; + } + ++ + static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check) + { + const char *value = check->value; +@@ -1316,18 +1368,40 @@ static int git_path_check_ident(struct attr_check_item *check) static struct attr_check *check; @@ -150,7 +253,7 @@ index c7d6a85..56b806b 100644 git_check_attr(istate, path, check); ccheck = check->items; -@@ -1348,6 +1400,9 @@ void convert_attrs(struct index_state *istate, +@@ -1348,6 +1422,9 @@ void convert_attrs(struct index_state *istate, ca->crlf_action = CRLF_TEXT_CRLF; } ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); @@ -160,7 +263,7 @@ index c7d6a85..56b806b 100644 /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; -@@ -1439,13 +1494,13 @@ int convert_to_git(struct index_state *istate, +@@ -1439,13 +1516,13 @@ int convert_to_git(struct index_state *istate, if (!ret && ca.drv && ca.drv->required) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -177,7 +280,7 @@ index c7d6a85..56b806b 100644 src = dst->buf; len = dst->len; } -@@ -1472,7 +1527,7 @@ void convert_to_git_filter_fd(struct index_state *istate, +@@ -1472,7 +1549,7 @@ void convert_to_git_filter_fd(struct index_state *istate, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL)) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -186,7 +289,7 @@ index c7d6a85..56b806b 100644 crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags); ident_to_git(dst->buf, dst->len, dst, ca.ident); } -@@ -1487,7 +1542,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1487,7 +1564,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, int ret = 0, ret_filter = 0; ret |= ident_to_worktree(src, len, dst, ca->ident); @@ -195,7 +298,7 @@ index c7d6a85..56b806b 100644 src = dst->buf; len = dst->len; } -@@ -1498,16 +1553,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1498,16 +1575,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, */ if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) { ret |= crlf_to_worktree(src, len, dst, ca->crlf_action); @@ -218,7 +321,7 @@ index c7d6a85..56b806b 100644 } ret_filter = apply_filter( -@@ -1546,7 +1604,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, +@@ -1546,7 +1626,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, convert_attrs(istate, &ca, path); ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1, NULL, NULL); @@ -227,7 +330,7 @@ index c7d6a85..56b806b 100644 src = dst->buf; len = dst->len; } -@@ -2058,3 +2116,96 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) +@@ -2058,3 +2138,107 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) return CA_CLASS_STREAMABLE; } @@ -241,7 +344,7 @@ index c7d6a85..56b806b 100644 + return; + + if (was_converted < 0) { -+ __chgfdccsid(fd, 1208); ++ __chgfdccsid(fd, utf8_ccsid); + __disableautocvt(fd); + return; + } @@ -249,7 +352,7 @@ index c7d6a85..56b806b 100644 + struct conv_attrs ca; + convert_attrs(istate, &ca, path); + if (ca.attr_action != CRLF_BINARY) { -+ if (ca.working_tree_encoding) { ++ if (ca.working_tree_encoding && !same_encoding(ca.working_tree_encoding, default_encoding)) { + __chgfdcodeset(fd, ca.working_tree_encoding); + } + else { @@ -304,6 +407,17 @@ index c7d6a85..56b806b 100644 + if ((file_ccsid == 819 || file_ccsid == 1208) && (attr_ccsid == 1208 || attr_ccsid == 819)) { + return; + } ++ ++ /* ++ * If we have an explicit working-tree-encoding, we should try to ++ * re-encode even if the file tag doesn't match perfectly. ++ * Our best-effort conversion (with TRANSLIT) will handle it. ++ */ ++ if (ca.working_tree_encoding) { ++ *autoconvertToASCII = 1; ++ return; ++ } ++ + // Don't check for binary files, just add them + if (attr_ccsid == FT_BINARY) + return; diff --git a/stable-patches/entry.c.patch b/stable-patches/entry.c.patch index 3664609..743ea49 100644 --- a/stable-patches/entry.c.patch +++ b/stable-patches/entry.c.patch @@ -1,5 +1,5 @@ diff --git a/entry.c b/entry.c -index 7817aee362..e977570d5c 100644 +index 7817aee..69568f1 100644 --- a/entry.c +++ b/entry.c @@ -85,8 +85,16 @@ static void remove_subtree(struct strbuf *path) @@ -93,27 +93,3 @@ index 7817aee362..e977570d5c 100644 if (!to_tempfile) fstat_done = fstat_checkout_output(fd, state, &st); close(fd); -@@ -486,6 +521,23 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, - static struct strbuf path = STRBUF_INIT; - struct stat st; - struct conv_attrs ca_buf; -+#ifdef __MVS__ -+ const char* git_utf8_ccsid_str = getenv("GIT_UTF8_CCSID"); -+ -+ if (git_utf8_ccsid_str != NULL) { -+ char* endptr; -+ errno = 0; -+ long conv = strtol(git_utf8_ccsid_str, &endptr, 10); -+ -+ if (!conv) { -+ perror("Error converting GIT_UTF8_CCSID to short"); -+ } else if (endptr == git_utf8_ccsid_str) { -+ fprintf(stderr, "No digits were found in GIT_UTF8_CCSID\n"); -+ } else { -+ utf8_ccsid = conv; -+ } -+ } -+#endif - - if (ce->ce_flags & CE_WT_REMOVE) { - if (topath) From 955f9c55464e337ffe32ddb91fbfcdf5505ec0b4 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Mon, 13 Apr 2026 01:19:46 -0400 Subject: [PATCH 06/12] Adding tests --- stable-patches/environment.c.patch | 12 +++- stable-patches/environment.h.patch | 5 +- stable-patches/lockfile.c.patch | 26 +++++-- stable-patches/t0082-zos-encoding.sh.patch | 6 +- stable-patches/utf8.c.patch | 84 +++++++++++++++++++++- stable-patches/utf8.h.patch | 35 ++++++++- 6 files changed, 152 insertions(+), 16 deletions(-) diff --git a/stable-patches/environment.c.patch b/stable-patches/environment.c.patch index 9675394..d43ac4b 100644 --- a/stable-patches/environment.c.patch +++ b/stable-patches/environment.c.patch @@ -1,5 +1,5 @@ diff --git a/environment.c b/environment.c -index 8ffbf92..bef0b5d 100644 +index 8ffbf92..dedabe1 100644 --- a/environment.c +++ b/environment.c @@ -26,6 +26,7 @@ @@ -10,18 +10,19 @@ index 8ffbf92..bef0b5d 100644 #include "fmt-merge-msg.h" #include "commit.h" #include "strvec.h" -@@ -57,6 +58,10 @@ char *git_attributes_file; +@@ -57,6 +58,11 @@ char *git_attributes_file; int zlib_compression_level = Z_BEST_SPEED; int pack_compression_level = Z_DEFAULT_COMPRESSION; int fsync_object_files = -1; +#ifdef __MVS__ +int ignore_file_tags = 0; ++int iconv_translit = 0; +int utf8_ccsid = 1208; +#endif int use_fsync = -1; enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT; enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT; -@@ -406,6 +411,18 @@ int git_default_core_config(const char *var, const char *value, +@@ -406,6 +412,23 @@ int git_default_core_config(const char *var, const char *value, return 0; } @@ -31,6 +32,11 @@ index 8ffbf92..bef0b5d 100644 + return 0; + } + ++ if (!strcmp(var, "core.iconvtranslit")) { ++ iconv_translit = git_config_bool(var, value); ++ return 0; ++ } ++ + if (!strcmp(var, "core.utf8ccsid")) { + utf8_ccsid = git_config_ulong(var, value, ctx->kvi); + return 0; diff --git a/stable-patches/environment.h.patch b/stable-patches/environment.h.patch index 25abba0..568521e 100644 --- a/stable-patches/environment.h.patch +++ b/stable-patches/environment.h.patch @@ -1,13 +1,14 @@ diff --git a/environment.h b/environment.h -index 27f657a..ae908b6 100644 +index 27f657a..3c8940f 100644 --- a/environment.h +++ b/environment.h -@@ -159,6 +159,9 @@ extern int zlib_compression_level; +@@ -159,6 +159,10 @@ extern int zlib_compression_level; extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; +#ifdef __MVS__ +extern int utf8_ccsid; ++extern int iconv_translit; +#endif extern int precomposed_unicode; extern int protect_hfs; diff --git a/stable-patches/lockfile.c.patch b/stable-patches/lockfile.c.patch index bd2bbb2..197e81e 100644 --- a/stable-patches/lockfile.c.patch +++ b/stable-patches/lockfile.c.patch @@ -1,15 +1,33 @@ diff --git a/lockfile.c b/lockfile.c -index 67082a9..ed44413 100644 +index 67082a9..d6977ae 100644 --- a/lockfile.c +++ b/lockfile.c -@@ -83,6 +83,11 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, +@@ -2,10 +2,13 @@ + * Copyright (c) 2005, Junio C Hamano + */ + ++#define USE_THE_REPOSITORY_VARIABLE ++ + #include "git-compat-util.h" + #include "abspath.h" + #include "gettext.h" + #include "lockfile.h" ++#include "environment.h" + + /* + * path = absolute or relative path name +@@ -83,6 +86,15 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, strbuf_addstr(&filename, LOCK_SUFFIX); lk->tempfile = create_tempfile_mode(filename.buf, mode); +#ifdef __MVS__ + struct stat st; -+ if (lk->tempfile && fstat(lk->tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) -+ __setfdbinary(lk->tempfile->fd); ++ if (lk->tempfile && fstat(lk->tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) { ++ if (flags & LOCK_TAG_TEXT) ++ __chgfdccsid(lk->tempfile->fd, utf8_ccsid); ++ else ++ __setfdbinary(lk->tempfile->fd); ++ } +#endif strbuf_release(&filename); return lk->tempfile ? lk->tempfile->fd : -1; diff --git a/stable-patches/t0082-zos-encoding.sh.patch b/stable-patches/t0082-zos-encoding.sh.patch index a8361d0..206ded3 100644 --- a/stable-patches/t0082-zos-encoding.sh.patch +++ b/stable-patches/t0082-zos-encoding.sh.patch @@ -1,10 +1,10 @@ diff --git a/t/t0082-zos-encoding.sh b/t/t0082-zos-encoding.sh new file mode 100755 -index 0000000..f0ec439 +index 0000000..ceb9791 --- /dev/null +++ b/t/t0082-zos-encoding.sh @@ -0,0 +1,49 @@ -+#!/bin/bash ++#!/usr/bin/env bash + +test_description='z/OS encoding failure handling and tagging' + @@ -17,7 +17,7 @@ index 0000000..f0ec439 + +test_expect_success 'setup repo with character not in IBM-1047' ' +git config core.ignorefiletags true && -+# C5 A7 is UTF-8 for ŧ. It does not exist in IBM-1047. ++# C5 A7 is UTF-8 for ŧ. It does not exist in IBM-1047. +printf "\xc5\xa7" >fail_blob.txt && +git add fail_blob.txt && +git commit -m "add utf8 blob" && diff --git a/stable-patches/utf8.c.patch b/stable-patches/utf8.c.patch index 6dbbe90..379aa50 100644 --- a/stable-patches/utf8.c.patch +++ b/stable-patches/utf8.c.patch @@ -1,8 +1,88 @@ diff --git a/utf8.c b/utf8.c -index 96460cc..5ab0f89 100644 +index 96460cc..573f198 100644 --- a/utf8.c +++ b/utf8.c -@@ -817,6 +817,30 @@ int skip_utf8_bom(char **text, size_t len) +@@ -1,6 +1,8 @@ + #define DISABLE_SIGN_COMPARE_WARNINGS ++#define USE_THE_REPOSITORY_VARIABLE + + #include "git-compat-util.h" ++#include "environment.h" + #include "strbuf.h" + #include "utf8.h" + +@@ -620,6 +622,70 @@ char *reencode_string_len(const char *in, size_t insz, + memcpy(out, bom_str, bom_len); + return out; + } ++ ++char *reencode_string_len_translit(const char *in, size_t insz, ++ const char *out_encoding, const char *in_encoding, ++ size_t *outsz) ++{ ++ iconv_t conv; ++ char *out; ++ const char *bom_str = NULL; ++ size_t bom_len = 0; ++ char *out_encoding_translit; ++ ++ if (!in_encoding) ++ return NULL; ++ ++ /* UTF-16LE-BOM is the same as UTF-16 for reading */ ++ if (same_utf_encoding("UTF-16LE-BOM", in_encoding)) ++ in_encoding = "UTF-16"; ++ ++ if (same_utf_encoding("UTF-16LE-BOM", out_encoding)) { ++ bom_str = utf16_le_bom; ++ bom_len = sizeof(utf16_le_bom); ++ out_encoding = "UTF-16LE"; ++ } else if (same_utf_encoding("UTF-16BE-BOM", out_encoding)) { ++ bom_str = utf16_be_bom; ++ bom_len = sizeof(utf16_be_bom); ++ out_encoding = "UTF-16BE"; ++#ifdef ICONV_OMITS_BOM ++ } else if (same_utf_encoding("UTF-16", out_encoding)) { ++ bom_str = utf16_be_bom; ++ bom_len = sizeof(utf16_be_bom); ++ out_encoding = "UTF-16BE"; ++ } else if (same_utf_encoding("UTF-32", out_encoding)) { ++ bom_str = utf32_be_bom; ++ bom_len = sizeof(utf32_be_bom); ++ out_encoding = "UTF-32BE"; ++#endif ++ } ++ ++ if (iconv_translit) { ++ out_encoding_translit = xstrfmt("%s//TRANSLIT", out_encoding); ++ conv = iconv_open(out_encoding_translit, in_encoding); ++ free(out_encoding_translit); ++ } else { ++ conv = iconv_open(out_encoding, in_encoding); ++ } ++ ++ if (conv == (iconv_t) -1) { ++ in_encoding = fallback_encoding(in_encoding); ++ if (iconv_translit) { ++ out_encoding_translit = xstrfmt("%s//TRANSLIT", fallback_encoding(out_encoding)); ++ conv = iconv_open(out_encoding_translit, in_encoding); ++ free(out_encoding_translit); ++ } else { ++ conv = iconv_open(fallback_encoding(out_encoding), in_encoding); ++ } ++ if (conv == (iconv_t) -1) ++ return NULL; ++ } ++ out = reencode_string_iconv(in, insz, conv, bom_len, outsz); ++ iconv_close(conv); ++ if (out && bom_str && bom_len) ++ memcpy(out, bom_str, bom_len); ++ return out; ++} + #endif + + static int has_bom_prefix(const char *data, size_t len, +@@ -817,6 +883,30 @@ int skip_utf8_bom(char **text, size_t len) return 1; } diff --git a/stable-patches/utf8.h.patch b/stable-patches/utf8.h.patch index bb0f64d..ce38d6b 100644 --- a/stable-patches/utf8.h.patch +++ b/stable-patches/utf8.h.patch @@ -1,9 +1,40 @@ diff --git a/utf8.h b/utf8.h -index cf8ecb0..d80d85a 100644 +index cf8ecb0..f06739b 100644 --- a/utf8.h +++ b/utf8.h -@@ -50,6 +50,10 @@ static inline char *reencode_string(const char *in, +@@ -32,11 +32,19 @@ char *reencode_string_len(const char *in, size_t insz, + const char *out_encoding, + const char *in_encoding, + size_t *outsz); ++char *reencode_string_len_translit(const char *in, size_t insz, ++ const char *out_encoding, ++ const char *in_encoding, ++ size_t *outsz); + #else + static inline char *reencode_string_len(const char *a UNUSED, size_t b UNUSED, + const char *c UNUSED, + const char *d UNUSED, size_t *e) + { if (e) *e = 0; return NULL; } ++static inline char *reencode_string_len_translit(const char *a UNUSED, size_t b UNUSED, ++ const char *c UNUSED, ++ const char *d UNUSED, size_t *e) ++{ if (e) *e = 0; return NULL; } + #endif + static inline char *reencode_string(const char *in, +@@ -48,8 +56,21 @@ static inline char *reencode_string(const char *in, + NULL); + } + ++static inline char *reencode_string_translit(const char *in, ++ const char *out_encoding, ++ const char *in_encoding) ++{ ++ return reencode_string_len_translit(in, strlen(in), ++ out_encoding, in_encoding, ++ NULL); ++} ++ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding); +void find_first_non_ascii(const char *src, size_t src_len, From eb59a72fbd685b7d4b653ad89d5520dc1dc46d6f Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Mon, 13 Apr 2026 01:20:22 -0400 Subject: [PATCH 07/12] add more tests --- stable-patches/config.c.patch | 22 +++++++++++++++++++ stable-patches/lockfile.h.patch | 16 ++++++++++++++ .../t-t5801-git-remote-testgit.patch | 10 +++++++++ 3 files changed, 48 insertions(+) create mode 100644 stable-patches/config.c.patch create mode 100644 stable-patches/lockfile.h.patch create mode 100644 stable-patches/t-t5801-git-remote-testgit.patch diff --git a/stable-patches/config.c.patch b/stable-patches/config.c.patch new file mode 100644 index 0000000..738963a --- /dev/null +++ b/stable-patches/config.c.patch @@ -0,0 +1,22 @@ +diff --git a/config.c b/config.c +index 7f6d53b..e497e5a 100644 +--- a/config.c ++++ b/config.c +@@ -2986,7 +2986,7 @@ int repo_config_set_multivar_in_file_gently(struct repository *r, + * The lock serves a purpose in addition to locking: the new + * contents of .git/config will be written into it. + */ +- fd = hold_lock_file_for_update(&lock, config_filename, 0); ++ fd = hold_lock_file_for_update(&lock, config_filename, LOCK_TAG_TEXT); + if (fd < 0) { + error_errno(_("could not lock config file %s"), config_filename); + ret = CONFIG_NO_LOCK; +@@ -3331,7 +3331,7 @@ static int repo_config_copy_or_rename_section_in_file( + if (!config_filename) + config_filename = filename_buf = repo_git_path(r, "config"); + +- out_fd = hold_lock_file_for_update(&lock, config_filename, 0); ++ out_fd = hold_lock_file_for_update(&lock, config_filename, LOCK_TAG_TEXT); + if (out_fd < 0) { + ret = error(_("could not lock config file %s"), config_filename); + goto out; diff --git a/stable-patches/lockfile.h.patch b/stable-patches/lockfile.h.patch new file mode 100644 index 0000000..d3ee99f --- /dev/null +++ b/stable-patches/lockfile.h.patch @@ -0,0 +1,16 @@ +diff --git a/lockfile.h b/lockfile.h +index 1bb9926..de6143c 100644 +--- a/lockfile.h ++++ b/lockfile.h +@@ -148,6 +148,11 @@ struct lock_file { + */ + #define LOCK_REPORT_ON_ERROR 4 + ++/* ++ * Tag the lockfile as text (UTF-8) on z/OS. If not set, the default is binary. ++ */ ++#define LOCK_TAG_TEXT 8 ++ + /* + * Usually symbolic links in the destination path are resolved. This + * means that (1) the lockfile is created by adding ".lock" to the diff --git a/stable-patches/t-t5801-git-remote-testgit.patch b/stable-patches/t-t5801-git-remote-testgit.patch new file mode 100644 index 0000000..7e54377 --- /dev/null +++ b/stable-patches/t-t5801-git-remote-testgit.patch @@ -0,0 +1,10 @@ +diff --git a/t/t5801/git-remote-testgit b/t/t5801/git-remote-testgit +index f8b4764..5eb2c0a 100755 +--- a/t/t5801/git-remote-testgit ++++ b/t/t5801/git-remote-testgit +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/usr/bin/env bash + # Copyright (c) 2012 Felipe Contreras + + # The first argument can be a url when the fetch/push command was a url From a320c7de2f8b30c8b3a8bf2bdf1cd01d7eb6644b Mon Sep 17 00:00:00 2001 From: Haritha <112700353+HarithaIBM@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:19:35 +0530 Subject: [PATCH 08/12] Update buildenv --- buildenv | 1 + 1 file changed, 1 insertion(+) diff --git a/buildenv b/buildenv index c8e242c..bf4f9c8 100644 --- a/buildenv +++ b/buildenv @@ -12,6 +12,7 @@ export ZOPEN_STABLE_URL="https://github.com/git/git.git" export ZOPEN_STABLE_TAG="v${GIT_VERSION}" export ZOPEN_STABLE_DEPS="curl git make m4 perl autoconf automake help2man texinfo xz zlib openssl expat gettext gzip tar coreutils zoslib diffutils ncurses bash sed libpcre2 tar check_python gawk zusage libpsl libssh2 libiconv" +export ZOPEN_CHECK_TIMEOUT="${ZOPEN_CHECK_NO_TIMEOUT}" # # Note the 'man' tarball release is numbered independently from the 'git' release. # From d5edd3df659e8ede08edcaae4c9ded70ce4805d3 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Fri, 17 Apr 2026 06:02:51 -0400 Subject: [PATCH 09/12] Enabled tests and fixed the exaction location of errors --- stable-patches/t0082-zos-encoding.sh.patch | 82 +++++++++++++--------- stable-patches/utf8.c.patch | 6 +- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/stable-patches/t0082-zos-encoding.sh.patch b/stable-patches/t0082-zos-encoding.sh.patch index 206ded3..20317bd 100644 --- a/stable-patches/t0082-zos-encoding.sh.patch +++ b/stable-patches/t0082-zos-encoding.sh.patch @@ -1,9 +1,9 @@ diff --git a/t/t0082-zos-encoding.sh b/t/t0082-zos-encoding.sh new file mode 100755 -index 0000000..ceb9791 +index 0000000..9bfe25e --- /dev/null +++ b/t/t0082-zos-encoding.sh -@@ -0,0 +1,49 @@ +@@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +test_description='z/OS encoding failure handling and tagging' @@ -12,44 +12,62 @@ index 0000000..ceb9791 + +# This test only makes sense on z/OS +if ! uname | grep -q "OS/390"; then -+test_done ++ test_done +fi + +test_expect_success 'setup repo with character not in IBM-1047' ' -+git config core.ignorefiletags true && -+# C5 A7 is UTF-8 for ŧ. It does not exist in IBM-1047. -+printf "\xc5\xa7" >fail_blob.txt && -+git add fail_blob.txt && -+git commit -m "add utf8 blob" && -+ -+# Set the attribute. On checkout, it will try to convert UTF-8 -> IBM-1047 and fail. -+echo "fail_blob.txt working-tree-encoding=IBM-1047" >.gitattributes && -+git add .gitattributes && -+git commit -m "add attributes" && -+git config core.ignorefiletags false ++ git config core.ignorefiletags true && ++ git config core.iconvtranslit false && ++ git config core.utf8ccsid 1208 && ++ # C5 A7 is UTF-8 for ŧ. It does not exist in IBM-1047. ++ printf "\xc5\xa7" >fail_blob.txt && ++ git add fail_blob.txt && ++ git commit -m "add utf8 blob" && ++ ++ # Set the attribute. On checkout, it will try to convert UTF-8 -> IBM-1047 and fail. ++ echo "fail_blob.txt working-tree-encoding=IBM-1047" >.gitattributes && ++ git add .gitattributes && ++ git commit -m "add attributes" && ++ git config core.ignorefiletags false +' + +test_expect_success 'checkout fails encoding but tags as 1208' ' -+rm fail_blob.txt && -+# Use checkout-index -f to ensure we really try to write the file -+git checkout-index -f fail_blob.txt 2>err && -+grep "failed to encode" err && -+grep "line 1, col 1" err && -+grep "char: 0xc5" err && -+ -+# Verify the tag using chtag -p -+chtag -p fail_blob.txt >tag_info && -+grep "t UTF-8" tag_info && -+grep "T=on" tag_info && -+ -+# Verify content is still raw UTF-8 -+printf "\xc5\xa7" >expected && -+test_cmp expected fail_blob.txt ++ rm fail_blob.txt && ++ # Use checkout-index -f to ensure we really try to write the file ++ git checkout-index -f fail_blob.txt 2>err && ++ grep "failed to encode" err && ++ grep "line 1, col 1" err && ++ grep "char: 0xc5" err && ++ ++ # Verify the tag using chtag -p ++ chtag -p fail_blob.txt >tag_info && ++ grep "t UTF-8" tag_info && ++ grep "T=on" tag_info && ++ ++ # Verify content is still raw UTF-8 ++ printf "\xc5\xa7" >expected && ++ test_cmp expected fail_blob.txt +' + -+test_expect_success 'git status remains clean after encoding failure' ' -+git status --porcelain -uno >status_out && -+test_must_be_empty status_out ++test_expect_success 'git status shows modified after encoding failure' ' ++ git status --porcelain -uno >status_out && ++ echo " M fail_blob.txt" >expected_status && ++ test_cmp expected_status status_out ++' ++ ++test_expect_success 'checkout succeeds with transliteration' ' ++ git config core.iconvtranslit true && ++ rm fail_blob.txt && ++ git checkout-index -f fail_blob.txt && ++ ++ # Verify the tag is now IBM-1047 ++ chtag -p fail_blob.txt >tag_info && ++ grep "t IBM-1047" tag_info && ++ ++ # Verify content is transliterated to "t" (0xa3 in IBM-1047) ++ printf "\xa3" >expected && ++ chtag -tc 1047 expected && ++ test_cmp expected fail_blob.txt +' + +test_done diff --git a/stable-patches/utf8.c.patch b/stable-patches/utf8.c.patch index 379aa50..85e3462 100644 --- a/stable-patches/utf8.c.patch +++ b/stable-patches/utf8.c.patch @@ -1,5 +1,5 @@ diff --git a/utf8.c b/utf8.c -index 96460cc..573f198 100644 +index 96460cc..6ddfac1 100644 --- a/utf8.c +++ b/utf8.c @@ -1,6 +1,8 @@ @@ -90,12 +90,12 @@ index 96460cc..573f198 100644 + size_t *line_out, size_t *col_out, + unsigned char *bad_char_out) +{ -+ size_t line = 1, col = 1; ++ size_t line = 1, col = 0; + unsigned char bad_char = 0; + for (size_t i = 0; i < src_len; i++) { + if (src[i] == '\n' || is_ebcdic_newline(src[i])) { + line++; -+ col = 1; ++ col = 0; + } else { + col++; + } From 4f9ea4b2c3ed1da398ff972143950e881093c94b Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Thu, 23 Apr 2026 08:28:26 -0400 Subject: [PATCH 10/12] Fix to handle openssl4.0.0 struct changes --- stable-patches/imap-send.c.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 stable-patches/imap-send.c.patch diff --git a/stable-patches/imap-send.c.patch b/stable-patches/imap-send.c.patch new file mode 100644 index 0000000..a723980 --- /dev/null +++ b/stable-patches/imap-send.c.patch @@ -0,0 +1,13 @@ +--- a/imap-send.c 2026-04-23 02:24:40 -0400 ++++ b/imap-send.c 2026-04-23 02:24:40 -0400 +@@ -246,8 +246,8 @@ + for (i = 0; !found && i < num_subj_alt_names; i++) { + GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); + if (subj_alt_name->type == GEN_DNS && +- strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length && +- host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data))) ++ strlen((const char *)ASN1_STRING_get0_data(subj_alt_name->d.ia5)) == (size_t)ASN1_STRING_length(subj_alt_name->d.ia5) && ++ host_matches(hostname, (const char *)(ASN1_STRING_get0_data(subj_alt_name->d.ia5)))) + found = 1; + } + sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free); From 5232f8cb558970aa104c6067b6a485f425dbe719 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Fri, 8 May 2026 06:16:19 -0400 Subject: [PATCH 11/12] Update patches with latest fixes and merge improvements --- stable-patches/builtin/index-pack.c.patch | 4 +- stable-patches/config.mak.uname.patch | 3 +- stable-patches/convert.c.patch | 48 +++++++----- stable-patches/run-command.c.patch | 20 ++--- stable-patches/utf8.c.patch | 90 ++++++++++++++++------- stable-patches/utf8.h.patch | 11 +-- 6 files changed, 113 insertions(+), 63 deletions(-) diff --git a/stable-patches/builtin/index-pack.c.patch b/stable-patches/builtin/index-pack.c.patch index 8c6bd06..7db3a16 100644 --- a/stable-patches/builtin/index-pack.c.patch +++ b/stable-patches/builtin/index-pack.c.patch @@ -7,7 +7,7 @@ index b67fb02..1918ff3 100644 for (i = 0; i < nr_threads; i++) { thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY); +#ifdef __MVS__ -+ __disableautocvt(thread_data[i].pack_fd); ++ /* __disableautocvt(thread_data[i].pack_fd); */ +#endif } @@ -25,7 +25,7 @@ index b67fb02..1918ff3 100644 } else { input_fd = xopen(pack_name, O_RDONLY); +#ifdef __MVS__ -+ __disableautocvt(input_fd); ++ /* __disableautocvt(input_fd); */ +#endif output_fd = -1; nothread_data.pack_fd = input_fd; diff --git a/stable-patches/config.mak.uname.patch b/stable-patches/config.mak.uname.patch index 1116d31..1c83579 100644 --- a/stable-patches/config.mak.uname.patch +++ b/stable-patches/config.mak.uname.patch @@ -1,8 +1,7 @@ diff --git a/config.mak.uname b/config.mak.uname -index 3c35ae3..d9aba56 100644 --- a/config.mak.uname +++ b/config.mak.uname -@@ -653,15 +653,25 @@ ifeq ($(uname_S),NONSTOP_KERNEL) +@@ -653,15 +653,25 @@ SHELL_PATH = /usr/coreutils/bin/bash endif ifeq ($(uname_S),OS/390) diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index f15f575..99244d9 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -1,5 +1,5 @@ diff --git a/convert.c b/convert.c -index c7d6a85..c57c165 100644 +index c7d6a85..93518eb 100644 --- a/convert.c +++ b/convert.c @@ -6,6 +6,7 @@ @@ -79,7 +79,7 @@ index c7d6a85..c57c165 100644 return 0; /* -@@ -411,8 +430,18 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -411,8 +430,25 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, return 0; trace_encoding("source", path, enc, src, src_len); @@ -94,11 +94,18 @@ index c7d6a85..c57c165 100644 + if (!dst) { + dst = reencode_string_len_translit(src, src_len, default_encoding, enc, + &dst_len); ++ if (dst) { ++ size_t line, col; ++ unsigned char bad_char; ++ find_first_encoding_error(src, src_len, default_encoding, enc, &line, &col, &bad_char); ++ warning(_("best-effort conversion used for '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"), ++ path, enc, default_encoding, line, col, bad_char); ++ } + } if (!dst) { /* * We could add the blob "as-is" to Git. However, on checkout -@@ -420,12 +449,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -420,12 +456,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, * would fail and we would leave the user with a messed-up * working tree. Let's try to avoid this by screaming loud. */ @@ -108,7 +115,7 @@ index c7d6a85..c57c165 100644 + } + size_t line, col; + unsigned char bad_char; -+ find_first_non_ascii(src, src_len, &line, &col, &bad_char); ++ find_first_encoding_error(src, src_len, default_encoding, enc, &line, &col, &bad_char); + + const char* msg = _("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"); if (die_on_error) @@ -122,7 +129,7 @@ index c7d6a85..c57c165 100644 } } trace_encoding("destination", path, default_encoding, dst, dst_len); -@@ -476,24 +512,40 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -476,24 +519,47 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, } static int encode_to_worktree(const char *path, const char *src, size_t src_len, @@ -157,18 +164,25 @@ index c7d6a85..c57c165 100644 - return 0; + dst = reencode_string_len_translit(src, src_len, enc, default_encoding, + &dst_len); ++ if (dst) { ++ size_t line, col; ++ unsigned char bad_char; ++ find_first_encoding_error(src, src_len, enc, default_encoding, &line, &col, &bad_char); ++ warning(_("best-effort conversion used for '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"), ++ path, default_encoding, enc, line, col, bad_char); ++ } + } + if (!dst) { + size_t line, col; + unsigned char bad_char; -+ find_first_non_ascii(src, src_len, &line, &col, &bad_char); ++ find_first_encoding_error(src, src_len, enc, default_encoding, &line, &col, &bad_char); + error(_("failed to encode '%s' from %s to %s at line %zu, col %zu (char: 0x%02x)"), + path, default_encoding, enc, line, col, bad_char); + return -1; } strbuf_attach(buf, dst, dst_len, dst_len + 1); -@@ -581,7 +633,7 @@ static int crlf_to_git(struct index_state *istate, +@@ -581,7 +647,7 @@ static int crlf_to_git(struct index_state *istate, } else { do { unsigned char c = *src++; @@ -177,7 +191,7 @@ index c7d6a85..c57c165 100644 *dst++ = c; } while (--len); } -@@ -608,14 +660,17 @@ static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf, +@@ -608,14 +674,17 @@ static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf, strbuf_grow(buf, len + stats.lonelf); for (;;) { @@ -197,7 +211,7 @@ index c7d6a85..c57c165 100644 } len -= nl + 1 - src; src = nl + 1; -@@ -1257,13 +1312,10 @@ static const char *git_path_check_encoding(struct attr_check_item *check) +@@ -1257,13 +1326,10 @@ static const char *git_path_check_encoding(struct attr_check_item *check) die(_("true/false are no valid working-tree-encodings")); } @@ -212,7 +226,7 @@ index c7d6a85..c57c165 100644 static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check) { const char *value = check->value; -@@ -1316,18 +1368,40 @@ static int git_path_check_ident(struct attr_check_item *check) +@@ -1316,18 +1382,40 @@ static int git_path_check_ident(struct attr_check_item *check) static struct attr_check *check; @@ -253,7 +267,7 @@ index c7d6a85..c57c165 100644 git_check_attr(istate, path, check); ccheck = check->items; -@@ -1348,6 +1422,9 @@ void convert_attrs(struct index_state *istate, +@@ -1348,6 +1436,9 @@ void convert_attrs(struct index_state *istate, ca->crlf_action = CRLF_TEXT_CRLF; } ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); @@ -263,7 +277,7 @@ index c7d6a85..c57c165 100644 /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; -@@ -1439,13 +1516,13 @@ int convert_to_git(struct index_state *istate, +@@ -1439,13 +1530,13 @@ int convert_to_git(struct index_state *istate, if (!ret && ca.drv && ca.drv->required) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -280,7 +294,7 @@ index c7d6a85..c57c165 100644 src = dst->buf; len = dst->len; } -@@ -1472,7 +1549,7 @@ void convert_to_git_filter_fd(struct index_state *istate, +@@ -1472,7 +1563,7 @@ void convert_to_git_filter_fd(struct index_state *istate, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL)) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -289,7 +303,7 @@ index c7d6a85..c57c165 100644 crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags); ident_to_git(dst->buf, dst->len, dst, ca.ident); } -@@ -1487,7 +1564,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1487,7 +1578,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, int ret = 0, ret_filter = 0; ret |= ident_to_worktree(src, len, dst, ca->ident); @@ -298,7 +312,7 @@ index c7d6a85..c57c165 100644 src = dst->buf; len = dst->len; } -@@ -1498,16 +1575,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1498,16 +1589,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, */ if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) { ret |= crlf_to_worktree(src, len, dst, ca->crlf_action); @@ -321,7 +335,7 @@ index c7d6a85..c57c165 100644 } ret_filter = apply_filter( -@@ -1546,7 +1626,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, +@@ -1546,7 +1640,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, convert_attrs(istate, &ca, path); ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1, NULL, NULL); @@ -330,7 +344,7 @@ index c7d6a85..c57c165 100644 src = dst->buf; len = dst->len; } -@@ -2058,3 +2138,107 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) +@@ -2058,3 +2152,107 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) return CA_CLASS_STREAMABLE; } diff --git a/stable-patches/run-command.c.patch b/stable-patches/run-command.c.patch index 604eaca..9c8add2 100644 --- a/stable-patches/run-command.c.patch +++ b/stable-patches/run-command.c.patch @@ -18,8 +18,8 @@ index e3e0247..ee3447b 100644 goto fail_pipe; } +#ifdef __MVS__ -+ __disableautocvt(fdin[0]); -+ __disableautocvt(fdin[1]); ++ /* __disableautocvt(fdin[0]); */ ++ /* __disableautocvt(fdin[1]); */ +#endif cmd->in = fdin[1]; } @@ -29,8 +29,8 @@ index e3e0247..ee3447b 100644 goto fail_pipe; } +#ifdef __MVS__ -+ __disableautocvt(fdout[0]); -+ __disableautocvt(fdout[1]); ++ /* __disableautocvt(fdout[0]); */ ++ /* __disableautocvt(fdout[1]); */ +#endif cmd->out = fdout[0]; } @@ -48,8 +48,8 @@ index e3e0247..ee3447b 100644 + goto fail_pipe; } +#ifdef __MVS__ -+ __disableautocvt(fderr[0]); -+ __disableautocvt(fderr[1]); ++ /* __disableautocvt(fderr[0]); */ ++ /* __disableautocvt(fderr[1]); */ +#endif cmd->err = fderr[0]; } @@ -67,8 +67,8 @@ index e3e0247..ee3447b 100644 return error_errno("cannot create pipe"); } +#ifdef __MVS__ -+ __disableautocvt(fdin[0]); -+ __disableautocvt(fdin[1]); ++ /* __disableautocvt(fdin[0]); */ ++ /* __disableautocvt(fdin[1]); */ +#endif async->in = fdin[1]; } @@ -78,8 +78,8 @@ index e3e0247..ee3447b 100644 return error_errno("cannot create pipe"); } +#ifdef __MVS__ -+ __disableautocvt(fdout[0]); -+ __disableautocvt(fdout[1]); ++ /* __disableautocvt(fdout[0]); */ ++ /* __disableautocvt(fdout[1]); */ +#endif async->out = fdout[0]; } diff --git a/stable-patches/utf8.c.patch b/stable-patches/utf8.c.patch index 85e3462..770c420 100644 --- a/stable-patches/utf8.c.patch +++ b/stable-patches/utf8.c.patch @@ -1,5 +1,5 @@ diff --git a/utf8.c b/utf8.c -index 96460cc..6ddfac1 100644 +index 96460cc..e99160a 100644 --- a/utf8.c +++ b/utf8.c @@ -1,6 +1,8 @@ @@ -11,9 +11,30 @@ index 96460cc..6ddfac1 100644 #include "strbuf.h" #include "utf8.h" -@@ -620,6 +622,70 @@ char *reencode_string_len(const char *in, size_t insz, - memcpy(out, bom_str, bom_len); - return out; +@@ -568,6 +570,20 @@ char *reencode_string_len(const char *in, size_t insz, + iconv_t conv; + char *out; + const char *bom_str = NULL; ++ ++#ifdef __MVS__ ++ if (utf8_ccsid == 819) { ++ /* HACK: For backwards compat UTF CCSID=819, ISO8859-1 really means utf-8 in the z/OS world */ ++ if (in_encoding && !strcasecmp("ISO8859-1", in_encoding)) { ++ in_encoding = "UTF-8"; ++ out_encoding = "UTF-8"; ++ } ++ if (out_encoding && !strcasecmp("ISO8859-1", out_encoding)) { ++ in_encoding = "UTF-8"; ++ out_encoding = "UTF-8"; ++ } ++ } ++#endif + size_t bom_len = 0; + + if (!in_encoding) +@@ -837,3 +853,116 @@ void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int wid + } else if (position == ALIGN_RIGHT) + strbuf_addf(buf, "%*s", width + utf8_compensation, s); } + +char *reencode_string_len_translit(const char *in, size_t insz, @@ -79,37 +100,52 @@ index 96460cc..6ddfac1 100644 + memcpy(out, bom_str, bom_len); + return out; +} - #endif - - static int has_bom_prefix(const char *data, size_t len, -@@ -817,6 +883,30 @@ int skip_utf8_bom(char **text, size_t len) - return 1; - } - -+void find_first_non_ascii(const char *src, size_t src_len, -+ size_t *line_out, size_t *col_out, -+ unsigned char *bad_char_out) ++ ++void find_first_encoding_error(const char *src, size_t src_len, ++ const char *to, const char *from, ++ size_t *line_out, size_t *col_out, ++ unsigned char *bad_char_out) +{ + size_t line = 1, col = 0; -+ unsigned char bad_char = 0; -+ for (size_t i = 0; i < src_len; i++) { -+ if (src[i] == '\n' || is_ebcdic_newline(src[i])) { ++ size_t fail_pos = src_len; ++ iconv_t cd = iconv_open(to, from); ++ ++ if (cd != (iconv_t)-1) { ++ const char *inbuf = src; ++ size_t inbytesleft = src_len; ++ char outbuf[256]; ++ char *outptr = outbuf; ++ size_t outbytesleft = sizeof(outbuf); ++ ++ while (inbytesleft > 0) { ++ size_t res = iconv(cd, (char **)&inbuf, &inbytesleft, &outptr, &outbytesleft); ++ if (res == (size_t)-1) { ++ if (errno == E2BIG) { ++ outptr = outbuf; ++ outbytesleft = sizeof(outbuf); ++ continue; ++ } ++ fail_pos = inbuf - src; ++ break; ++ } ++ outptr = outbuf; ++ outbytesleft = sizeof(outbuf); ++ } ++ iconv_close(cd); ++ } ++ ++ for (size_t i = 0; i < fail_pos; i++) { ++ if (src[i] == '\n') { + line++; + col = 0; + } else { + col++; + } -+ /* Try to find the first character that iconv would reject (non-ASCII) */ -+ if ((unsigned char)src[i] > 0x7F) { -+ bad_char = (unsigned char)src[i]; -+ break; -+ } ++ } ++ if (fail_pos < src_len) { ++ *bad_char_out = (unsigned char)src[fail_pos]; ++ col++; + } + *line_out = line; + *col_out = col; -+ *bad_char_out = bad_char; +} -+ - void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width, - const char *s) - { diff --git a/stable-patches/utf8.h.patch b/stable-patches/utf8.h.patch index ce38d6b..13ee29a 100644 --- a/stable-patches/utf8.h.patch +++ b/stable-patches/utf8.h.patch @@ -1,5 +1,5 @@ diff --git a/utf8.h b/utf8.h -index cf8ecb0..f06739b 100644 +index cf8ecb0..1485556 100644 --- a/utf8.h +++ b/utf8.h @@ -32,11 +32,19 @@ char *reencode_string_len(const char *in, size_t insz, @@ -22,7 +22,7 @@ index cf8ecb0..f06739b 100644 #endif static inline char *reencode_string(const char *in, -@@ -48,8 +56,21 @@ static inline char *reencode_string(const char *in, +@@ -48,8 +56,22 @@ static inline char *reencode_string(const char *in, NULL); } @@ -37,9 +37,10 @@ index cf8ecb0..f06739b 100644 + int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding); -+void find_first_non_ascii(const char *src, size_t src_len, -+ size_t *line_out, size_t *col_out, -+ unsigned char *bad_char_out); ++void find_first_encoding_error(const char *src, size_t src_len, ++ const char *to, const char *from, ++ size_t *line_out, size_t *col_out, ++ unsigned char *bad_char_out); + /* * Returns true if the path would match ".git" after HFS case-folding. From 1ed461947e26f0409e0a2d883feefd7577900aa9 Mon Sep 17 00:00:00 2001 From: D Harithamma Date: Wed, 13 May 2026 00:01:54 -0400 Subject: [PATCH 12/12] Update stable-patches with Python path fix and UTF-8 improvements --- stable-patches/Makefile.patch | 20 +- stable-patches/apply.c.patch | 4 +- stable-patches/attr.c.patch | 8 +- stable-patches/blame.c.patch | 2 +- stable-patches/builtin/cat-file.c.patch | 2 +- .../builtin/{help.c => help.c.patch} | 16 +- stable-patches/builtin/index-pack.c.patch | 21 +- stable-patches/config.c.patch | 2 +- stable-patches/config.mak.uname.patch | 5 +- stable-patches/configure.ac.patch | 2 +- stable-patches/convert.c.patch | 48 ++-- stable-patches/convert.h.patch | 2 +- stable-patches/date.c.patch | 6 +- stable-patches/diff.c.patch | 10 +- stable-patches/environment.c.patch | 6 +- stable-patches/environment.h.patch | 4 +- stable-patches/generate-perl.sh.patch | 2 +- stable-patches/git-compat-util.h.patch | 4 +- stable-patches/http.c.patch | 6 +- stable-patches/imap-send.c.patch | 24 +- stable-patches/lockfile.c.patch | 43 ++- stable-patches/lockfile.h.patch | 4 +- stable-patches/object-file.c.patch | 260 +----------------- stable-patches/odb.c.patch | 205 +------------- stable-patches/read-cache-ll.h.patch | 4 +- stable-patches/read-cache.c.patch | 4 +- stable-patches/repository.c.patch | 8 +- stable-patches/run-command.c.patch | 16 +- stable-patches/strbuf.c.patch | 0 stable-patches/t-meson.build.patch | 4 +- stable-patches/test-lib.sh.patch | 10 +- stable-patches/utf8.c.patch | 48 +++- 32 files changed, 210 insertions(+), 590 deletions(-) rename stable-patches/builtin/{help.c => help.c.patch} (71%) delete mode 100644 stable-patches/strbuf.c.patch diff --git a/stable-patches/Makefile.patch b/stable-patches/Makefile.patch index 6541fa8..c01a8a7 100644 --- a/stable-patches/Makefile.patch +++ b/stable-patches/Makefile.patch @@ -1,7 +1,7 @@ -diff --git i/Makefile w/Makefile -index 7e0f77e298..9a6c598885 100644 ---- i/Makefile -+++ w/Makefile +diff --git a/Makefile b/Makefile +index cedc234..dae1cf5 100644 +--- a/Makefile ++++ b/Makefile @@ -20,6 +20,8 @@ include shared.mak # # Define SHELL_PATH to a POSIX shell if your /bin/sh is broken. @@ -11,7 +11,7 @@ index 7e0f77e298..9a6c598885 100644 # Define SANE_TOOL_PATH to a colon-separated list of paths to prepend # to PATH if your tools in /usr/bin are broken. # -@@ -214,6 +216,8 @@ include shared.mak +@@ -224,6 +226,8 @@ include shared.mak # # Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl). # @@ -20,7 +20,7 @@ index 7e0f77e298..9a6c598885 100644 # Define NO_PERL if you do not want Perl scripts or libraries at all. # # Define NO_PERL_CPAN_FALLBACKS if you do not want to install bundled -@@ -914,15 +918,22 @@ BINDIR_PROGRAMS_NO_X += git-cvsserver +@@ -927,15 +931,22 @@ BINDIR_PROGRAMS_NO_X += git-cvsserver ifndef SHELL_PATH SHELL_PATH = /bin/sh endif @@ -43,7 +43,7 @@ index 7e0f77e298..9a6c598885 100644 TEST_SHELL_PATH = $(SHELL_PATH) -@@ -941,7 +952,7 @@ RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a +@@ -954,7 +965,7 @@ RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a endif GITLIBS = common-main.o $(LIB_FILE) @@ -52,7 +52,7 @@ index 7e0f77e298..9a6c598885 100644 GIT_USER_AGENT = git/$(GIT_VERSION) -@@ -2409,9 +2420,10 @@ perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative)) +@@ -2467,9 +2478,10 @@ perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative)) gitwebdir_SQ = $(subst ','\'',$(gitwebdir)) gitwebstaticdir_SQ = $(subst ','\'',$(gitwebstaticdir)) @@ -64,7 +64,7 @@ index 7e0f77e298..9a6c598885 100644 PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH)) TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) DIFF_SQ = $(subst ','\'',$(DIFF)) -@@ -2654,7 +2666,7 @@ hook-list.h: generate-hooklist.sh Documentation/githooks.adoc +@@ -2714,7 +2726,7 @@ hook-list.h: tools/generate-hooklist.sh Documentation/githooks.adoc SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\ $(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\ @@ -73,7 +73,7 @@ index 7e0f77e298..9a6c598885 100644 $(perllibdir_SQ) GIT-SCRIPT-DEFINES: FORCE @FLAGS='$(SCRIPT_DEFINES)'; \ -@@ -2884,7 +2896,7 @@ endif +@@ -2948,7 +2960,7 @@ endif exec-cmd.sp exec-cmd.s exec-cmd.o: GIT-PREFIX exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \ diff --git a/stable-patches/apply.c.patch b/stable-patches/apply.c.patch index 58b747d..d39151e 100644 --- a/stable-patches/apply.c.patch +++ b/stable-patches/apply.c.patch @@ -1,5 +1,5 @@ diff --git a/apply.c b/apply.c -index 3de4aa4..031a6e1 100644 +index 4aa1694..2d0ccd6 100644 --- a/apply.c +++ b/apply.c @@ -33,6 +33,7 @@ @@ -10,7 +10,7 @@ index 3de4aa4..031a6e1 100644 #include "apply.h" #include "entry.h" #include "setup.h" -@@ -4446,12 +4447,23 @@ static int try_create_file(struct apply_state *state, const char *path, +@@ -4521,12 +4522,23 @@ static int try_create_file(struct apply_state *state, const char *path, if (fd < 0) return 1; diff --git a/stable-patches/attr.c.patch b/stable-patches/attr.c.patch index 3166bbb..beadabd 100644 --- a/stable-patches/attr.c.patch +++ b/stable-patches/attr.c.patch @@ -1,7 +1,7 @@ -diff --git i/attr.c w/attr.c -index 0bd2750..9e17884 100644 ---- i/attr.c -+++ w/attr.c +diff --git a/attr.c b/attr.c +index 7536954..b15e1aa 100644 +--- a/attr.c ++++ b/attr.c @@ -873,9 +873,10 @@ static struct attr_stack *read_attr(struct index_state *istate, const char *git_attr_system_file(void) diff --git a/stable-patches/blame.c.patch b/stable-patches/blame.c.patch index 4d30a07..3d8464f 100644 --- a/stable-patches/blame.c.patch +++ b/stable-patches/blame.c.patch @@ -1,5 +1,5 @@ diff --git a/blame.c b/blame.c -index cb0b083..eb7dad0 100644 +index a3c49d1..d4bc3ae 100644 --- a/blame.c +++ b/blame.c @@ -274,6 +274,11 @@ static struct commit *fake_working_tree_commit(struct repository *r, diff --git a/stable-patches/builtin/cat-file.c.patch b/stable-patches/builtin/cat-file.c.patch index b278bc5..893abf7 100644 --- a/stable-patches/builtin/cat-file.c.patch +++ b/stable-patches/builtin/cat-file.c.patch @@ -1,5 +1,5 @@ diff --git a/builtin/cat-file.c b/builtin/cat-file.c -index df8e87a..d40b845 100644 +index d9fbad5..6f975e6 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -83,7 +83,8 @@ static int filter_object(const char *path, unsigned mode, diff --git a/stable-patches/builtin/help.c b/stable-patches/builtin/help.c.patch similarity index 71% rename from stable-patches/builtin/help.c rename to stable-patches/builtin/help.c.patch index 3aee449..0fe50a9 100644 --- a/stable-patches/builtin/help.c +++ b/stable-patches/builtin/help.c.patch @@ -1,8 +1,8 @@ -diff --git i/builtin/help.c w/builtin/help.c -index c257079..9ae3815 100644 ---- i/builtin/help.c -+++ w/builtin/help.c -@@ -313,6 +313,14 @@ static void exec_man_man(const char *path, const char *page) +diff --git a/builtin/help.c b/builtin/help.c +index c0aece4..fd18dad 100644 +--- a/builtin/help.c ++++ b/builtin/help.c +@@ -338,6 +338,14 @@ static void exec_man_man(const char *path, const char *page) warning_errno(_("failed to exec '%s'"), path); } @@ -17,7 +17,7 @@ index c257079..9ae3815 100644 static void exec_man_cmd(const char *cmd, const char *page) { struct strbuf shell_cmd = STRBUF_INIT; -@@ -335,6 +343,7 @@ static int supported_man_viewer(const char *name, size_t len) +@@ -360,6 +368,7 @@ static int supported_man_viewer(const char *name, size_t len) { return (!strncasecmp("man", name, len) || !strncasecmp("woman", name, len) || @@ -25,14 +25,14 @@ index c257079..9ae3815 100644 !strncasecmp("konqueror", name, len)); } -@@ -478,6 +487,13 @@ static void exec_viewer(const char *name, const char *page) +@@ -503,6 +512,13 @@ static void exec_viewer(const char *name, const char *page) { const char *info = get_man_viewer_info(name); +#ifdef __MVS__ + if (!strcasecmp(name, "man")) + exec_man_zotman(info, page); -+ if (!strcasecmp(name, "zotman")) ++ else if (!strcasecmp(name, "zotman")) + exec_man_zotman(info, page); + else +#endif diff --git a/stable-patches/builtin/index-pack.c.patch b/stable-patches/builtin/index-pack.c.patch index 7db3a16..e1c5c92 100644 --- a/stable-patches/builtin/index-pack.c.patch +++ b/stable-patches/builtin/index-pack.c.patch @@ -1,18 +1,8 @@ diff --git a/builtin/index-pack.c b/builtin/index-pack.c -index b67fb02..1918ff3 100644 +index ca7784d..f043465 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c -@@ -212,6 +212,9 @@ static void init_thread(void) - CALLOC_ARRAY(thread_data, nr_threads); - for (i = 0; i < nr_threads; i++) { - thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY); -+#ifdef __MVS__ -+ /* __disableautocvt(thread_data[i].pack_fd); */ -+#endif - } - - threads_active = 1; -@@ -368,10 +371,17 @@ static const char *open_pack_file(const char *pack_name) +@@ -368,6 +368,10 @@ static const char *open_pack_file(const char *pack_name) pack_name = strbuf_detach(&tmp_file, NULL); } else { output_fd = xopen(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); @@ -23,10 +13,3 @@ index b67fb02..1918ff3 100644 } nothread_data.pack_fd = output_fd; } else { - input_fd = xopen(pack_name, O_RDONLY); -+#ifdef __MVS__ -+ /* __disableautocvt(input_fd); */ -+#endif - output_fd = -1; - nothread_data.pack_fd = input_fd; - } diff --git a/stable-patches/config.c.patch b/stable-patches/config.c.patch index 738963a..d5af1e8 100644 --- a/stable-patches/config.c.patch +++ b/stable-patches/config.c.patch @@ -1,5 +1,5 @@ diff --git a/config.c b/config.c -index 7f6d53b..e497e5a 100644 +index 156f2a2..3cbca3a 100644 --- a/config.c +++ b/config.c @@ -2986,7 +2986,7 @@ int repo_config_set_multivar_in_file_gently(struct repository *r, diff --git a/stable-patches/config.mak.uname.patch b/stable-patches/config.mak.uname.patch index 1c83579..afb0190 100644 --- a/stable-patches/config.mak.uname.patch +++ b/stable-patches/config.mak.uname.patch @@ -1,7 +1,8 @@ diff --git a/config.mak.uname b/config.mak.uname +index 5feb582..d422080 100644 --- a/config.mak.uname +++ b/config.mak.uname -@@ -653,15 +653,25 @@ +@@ -655,15 +655,25 @@ ifeq ($(uname_S),NONSTOP_KERNEL) SHELL_PATH = /usr/coreutils/bin/bash endif ifeq ($(uname_S),OS/390) @@ -10,7 +11,7 @@ diff --git a/config.mak.uname b/config.mak.uname + SHELL_PATH = $(BASH_HOME)/bin/bash + TEST_SHELL_PATH = $(SHELL_PATH) + SHELL_PATH_FOR_SCRIPTS = /bin/env bash -+ PYTHON_PATH = /home/opnzos/local/pyz/bin/python ++ PYTHON_PATH := $(PYTHON_PATH)/python3 NO_SYS_POLL_H = YesPlease + RUNTIME_PREFIX = YesPlease NO_STRCASESTR = YesPlease diff --git a/stable-patches/configure.ac.patch b/stable-patches/configure.ac.patch index 8790ce8..1312d76 100644 --- a/stable-patches/configure.ac.patch +++ b/stable-patches/configure.ac.patch @@ -1,5 +1,5 @@ diff --git a/configure.ac b/configure.ac -index 38ff866..c9cf5ac 100644 +index cfb5011..2d967f9 100644 --- a/configure.ac +++ b/configure.ac @@ -463,6 +463,9 @@ else diff --git a/stable-patches/convert.c.patch b/stable-patches/convert.c.patch index 99244d9..7529e2c 100644 --- a/stable-patches/convert.c.patch +++ b/stable-patches/convert.c.patch @@ -1,5 +1,5 @@ diff --git a/convert.c b/convert.c -index c7d6a85..93518eb 100644 +index eae36c8..64a911a 100644 --- a/convert.c +++ b/convert.c @@ -6,6 +6,7 @@ @@ -79,16 +79,17 @@ index c7d6a85..93518eb 100644 return 0; /* -@@ -411,8 +430,25 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -411,8 +430,26 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, return 0; trace_encoding("source", path, enc, src, src_len); + + #ifdef __MVS__ -+ // If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files -+ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) -+ return 0; ++ /* If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files */ ++ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) ++ return 0; + #endif ++ dst = reencode_string_len(src, src_len, default_encoding, enc, &dst_len); + if (!dst) { @@ -105,7 +106,7 @@ index c7d6a85..93518eb 100644 if (!dst) { /* * We could add the blob "as-is" to Git. However, on checkout -@@ -420,12 +456,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -420,12 +457,19 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, * would fail and we would leave the user with a messed-up * working tree. Let's try to avoid this by screaming loud. */ @@ -129,7 +130,7 @@ index c7d6a85..93518eb 100644 } } trace_encoding("destination", path, default_encoding, dst, dst_len); -@@ -476,24 +519,47 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, +@@ -476,24 +520,48 @@ static int encode_to_git(const char *path, const char *src, size_t src_len, } static int encode_to_worktree(const char *path, const char *src, size_t src_len, @@ -149,13 +150,14 @@ index c7d6a85..93518eb 100644 */ - if (!enc || (src && !src_len)) + if (!enc || same_encoding(enc, default_encoding) || (src && !src_len)) - return 0; - ++ return 0; ++ + #ifdef __MVS__ -+ // If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files -+ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) -+ return 0; ++ /* If UTF CCSID == 819 (ISO8859-1), do not convert ISO8859-1 tagged files */ ++ if (utf8_ccsid == 819 && strcasecmp("ISO8859-1", enc) == 0) + return 0; + #endif + dst = reencode_string_len(src, src_len, enc, default_encoding, &dst_len); if (!dst) { @@ -182,7 +184,7 @@ index c7d6a85..93518eb 100644 } strbuf_attach(buf, dst, dst_len, dst_len + 1); -@@ -581,7 +647,7 @@ static int crlf_to_git(struct index_state *istate, +@@ -581,7 +649,7 @@ static int crlf_to_git(struct index_state *istate, } else { do { unsigned char c = *src++; @@ -191,7 +193,7 @@ index c7d6a85..93518eb 100644 *dst++ = c; } while (--len); } -@@ -608,14 +674,17 @@ static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf, +@@ -608,14 +676,17 @@ static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf, strbuf_grow(buf, len + stats.lonelf); for (;;) { @@ -211,7 +213,7 @@ index c7d6a85..93518eb 100644 } len -= nl + 1 - src; src = nl + 1; -@@ -1257,13 +1326,10 @@ static const char *git_path_check_encoding(struct attr_check_item *check) +@@ -1259,13 +1330,10 @@ static const char *git_path_check_encoding(struct attr_check_item *check) die(_("true/false are no valid working-tree-encodings")); } @@ -226,7 +228,7 @@ index c7d6a85..93518eb 100644 static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check) { const char *value = check->value; -@@ -1316,18 +1382,40 @@ static int git_path_check_ident(struct attr_check_item *check) +@@ -1318,18 +1386,40 @@ static int git_path_check_ident(struct attr_check_item *check) static struct attr_check *check; @@ -267,7 +269,7 @@ index c7d6a85..93518eb 100644 git_check_attr(istate, path, check); ccheck = check->items; -@@ -1348,6 +1436,9 @@ void convert_attrs(struct index_state *istate, +@@ -1350,6 +1440,9 @@ void convert_attrs(struct index_state *istate, ca->crlf_action = CRLF_TEXT_CRLF; } ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); @@ -277,7 +279,7 @@ index c7d6a85..93518eb 100644 /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; -@@ -1439,13 +1530,13 @@ int convert_to_git(struct index_state *istate, +@@ -1441,13 +1534,13 @@ int convert_to_git(struct index_state *istate, if (!ret && ca.drv && ca.drv->required) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -294,7 +296,7 @@ index c7d6a85..93518eb 100644 src = dst->buf; len = dst->len; } -@@ -1472,7 +1563,7 @@ void convert_to_git_filter_fd(struct index_state *istate, +@@ -1474,7 +1567,7 @@ void convert_to_git_filter_fd(struct index_state *istate, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL, NULL)) die(_("%s: clean filter '%s' failed"), path, ca.drv->name); @@ -303,7 +305,7 @@ index c7d6a85..93518eb 100644 crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags); ident_to_git(dst->buf, dst->len, dst, ca.ident); } -@@ -1487,7 +1578,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1489,7 +1582,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, int ret = 0, ret_filter = 0; ret |= ident_to_worktree(src, len, dst, ca->ident); @@ -312,7 +314,7 @@ index c7d6a85..93518eb 100644 src = dst->buf; len = dst->len; } -@@ -1498,16 +1589,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, +@@ -1500,16 +1593,19 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca, */ if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) { ret |= crlf_to_worktree(src, len, dst, ca->crlf_action); @@ -335,7 +337,7 @@ index c7d6a85..93518eb 100644 } ret_filter = apply_filter( -@@ -1546,7 +1640,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, +@@ -1548,7 +1644,7 @@ int renormalize_buffer(struct index_state *istate, const char *path, convert_attrs(istate, &ca, path); ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1, NULL, NULL); @@ -344,7 +346,7 @@ index c7d6a85..93518eb 100644 src = dst->buf; len = dst->len; } -@@ -2058,3 +2152,107 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) +@@ -2060,3 +2156,107 @@ enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca) return CA_CLASS_STREAMABLE; } diff --git a/stable-patches/convert.h.patch b/stable-patches/convert.h.patch index a9d8a81..8345cdb 100644 --- a/stable-patches/convert.h.patch +++ b/stable-patches/convert.h.patch @@ -1,5 +1,5 @@ diff --git a/convert.h b/convert.h -index 0a6e408..dcab447 100644 +index 0a6e408..9ae5fca 100644 --- a/convert.h +++ b/convert.h @@ -237,4 +237,9 @@ enum conv_attrs_classification { diff --git a/stable-patches/date.c.patch b/stable-patches/date.c.patch index dc62601..b3a2e77 100644 --- a/stable-patches/date.c.patch +++ b/stable-patches/date.c.patch @@ -1,7 +1,7 @@ -diff --git i/date.c w/date.c +diff --git a/date.c b/date.c index 17a9507..be63eb6 100644 ---- i/date.c -+++ w/date.c +--- a/date.c ++++ b/date.c @@ -6,12 +6,18 @@ #define DISABLE_SIGN_COMPARE_WARNINGS diff --git a/stable-patches/diff.c.patch b/stable-patches/diff.c.patch index 50ef6eb..69a00e3 100644 --- a/stable-patches/diff.c.patch +++ b/stable-patches/diff.c.patch @@ -1,8 +1,8 @@ diff --git a/diff.c b/diff.c -index a68ddd2..3054b38 100644 +index 397e38b..3fbd3e0 100644 --- a/diff.c +++ b/diff.c -@@ -4194,6 +4194,7 @@ int diff_populate_filespec(struct repository *r, +@@ -4478,6 +4478,7 @@ int diff_populate_filespec(struct repository *r, int check_binary = options ? options->check_binary : 0; int err = 0; int conv_flags = global_conv_flags_eol; @@ -10,7 +10,7 @@ index a68ddd2..3054b38 100644 /* * demote FAIL to WARN to allow inspecting the situation * instead of refusing. -@@ -4267,9 +4268,18 @@ int diff_populate_filespec(struct repository *r, +@@ -4551,9 +4552,18 @@ int diff_populate_filespec(struct repository *r, s->is_binary = 1; return 0; } @@ -29,7 +29,7 @@ index a68ddd2..3054b38 100644 s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); s->should_munmap = 1; -@@ -4277,7 +4287,7 @@ int diff_populate_filespec(struct repository *r, +@@ -4561,7 +4571,7 @@ int diff_populate_filespec(struct repository *r, /* * Convert from working tree format to canonical git format */ @@ -38,7 +38,7 @@ index a68ddd2..3054b38 100644 size_t size = 0; munmap(s->data, s->size); s->should_munmap = 0; -@@ -4369,13 +4379,21 @@ static void prep_temp_blob(struct index_state *istate, +@@ -4653,13 +4663,21 @@ static void prep_temp_blob(struct index_state *istate, temp->tempfile = mks_tempfile_dt("git-blob-XXXXXX", base); if (!temp->tempfile) die_errno("unable to create temp-file"); diff --git a/stable-patches/environment.c.patch b/stable-patches/environment.c.patch index d43ac4b..d6e7e3f 100644 --- a/stable-patches/environment.c.patch +++ b/stable-patches/environment.c.patch @@ -1,8 +1,8 @@ diff --git a/environment.c b/environment.c -index 8ffbf92..dedabe1 100644 +index fc3ed8b..705ad82 100644 --- a/environment.c +++ b/environment.c -@@ -26,6 +26,7 @@ +@@ -27,6 +27,7 @@ #include "repository.h" #include "config.h" #include "refs.h" @@ -10,7 +10,7 @@ index 8ffbf92..dedabe1 100644 #include "fmt-merge-msg.h" #include "commit.h" #include "strvec.h" -@@ -57,6 +58,11 @@ char *git_attributes_file; +@@ -57,6 +58,11 @@ char *apply_default_ignorewhitespace; int zlib_compression_level = Z_BEST_SPEED; int pack_compression_level = Z_DEFAULT_COMPRESSION; int fsync_object_files = -1; diff --git a/stable-patches/environment.h.patch b/stable-patches/environment.h.patch index 568521e..f159e68 100644 --- a/stable-patches/environment.h.patch +++ b/stable-patches/environment.h.patch @@ -1,8 +1,8 @@ diff --git a/environment.h b/environment.h -index 27f657a..3c8940f 100644 +index 123a71c..811cfba 100644 --- a/environment.h +++ b/environment.h -@@ -159,6 +159,10 @@ extern int zlib_compression_level; +@@ -174,6 +174,10 @@ extern int zlib_compression_level; extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; diff --git a/stable-patches/generate-perl.sh.patch b/stable-patches/generate-perl.sh.patch index c4f9e52..9d8e344 100644 --- a/stable-patches/generate-perl.sh.patch +++ b/stable-patches/generate-perl.sh.patch @@ -1,5 +1,5 @@ diff --git a/tools/generate-perl.sh b/tools/generate-perl.sh -index 796d835932..4441891559 100755 +index 796d835..4441891 100755 --- a/tools/generate-perl.sh +++ b/tools/generate-perl.sh @@ -19,7 +19,7 @@ OUTPUT="$5" diff --git a/stable-patches/git-compat-util.h.patch b/stable-patches/git-compat-util.h.patch index 73704ff..d0a62c8 100644 --- a/stable-patches/git-compat-util.h.patch +++ b/stable-patches/git-compat-util.h.patch @@ -1,8 +1,8 @@ diff --git a/git-compat-util.h b/git-compat-util.h -index bebcf9f..74776ff 100644 +index ae1bdc9..3b749ca 100644 --- a/git-compat-util.h +++ b/git-compat-util.h -@@ -371,6 +371,14 @@ static inline int git_has_dir_sep(const char *path) +@@ -363,6 +363,14 @@ static inline int git_has_dir_sep(const char *path) #endif #endif diff --git a/stable-patches/http.c.patch b/stable-patches/http.c.patch index 1788c6e..7ec7366 100644 --- a/stable-patches/http.c.patch +++ b/stable-patches/http.c.patch @@ -1,8 +1,8 @@ diff --git a/http.c b/http.c -index c8fc15aa11..d72d87f27e 100644 +index 67c9c6f..8eb2283 100644 --- a/http.c +++ b/http.c -@@ -1073,7 +1073,6 @@ static CURL *get_curl_handle(void) +@@ -1107,7 +1107,6 @@ static CURL *get_curl_handle(void) if (ssl_cipherlist != NULL && *ssl_cipherlist) curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST, ssl_cipherlist); @@ -10,7 +10,7 @@ index c8fc15aa11..d72d87f27e 100644 if (ssl_cert) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); if (ssl_cert_type) -@@ -1336,6 +1335,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) +@@ -1409,6 +1408,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE"); set_from_env(&ssl_capath, "GIT_SSL_CAPATH"); set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO"); diff --git a/stable-patches/imap-send.c.patch b/stable-patches/imap-send.c.patch index a723980..3bb8359 100644 --- a/stable-patches/imap-send.c.patch +++ b/stable-patches/imap-send.c.patch @@ -1,13 +1,21 @@ ---- a/imap-send.c 2026-04-23 02:24:40 -0400 -+++ b/imap-send.c 2026-04-23 02:24:40 -0400 -@@ -246,8 +246,8 @@ +diff --git a/imap-send.c b/imap-send.c +index af02c6a..7e1069e 100644 +--- a/imap-send.c ++++ b/imap-send.c +@@ -254,11 +254,13 @@ static int verify_hostname(X509 *cert, const char *hostname) + if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) { + int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names); for (i = 0; !found && i < num_subj_alt_names; i++) { +- int ntype; GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); - if (subj_alt_name->type == GEN_DNS && -- strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length && -- host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data))) -+ strlen((const char *)ASN1_STRING_get0_data(subj_alt_name->d.ia5)) == (size_t)ASN1_STRING_length(subj_alt_name->d.ia5) && -+ host_matches(hostname, (const char *)(ASN1_STRING_get0_data(subj_alt_name->d.ia5)))) +- ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype); + +- if (ntype == GEN_DNS && host_matches(hostname, subj_alt_str)) ++ if (subj_alt_name->type == GEN_DNS && ++ strlen((const char *)ASN1_STRING_get0_data(subj_alt_name->d.ia5)) == ++ (size_t)ASN1_STRING_length(subj_alt_name->d.ia5) && ++ host_matches(hostname, ++ (const char *)ASN1_STRING_get0_data(subj_alt_name->d.ia5))) found = 1; } sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free); diff --git a/stable-patches/lockfile.c.patch b/stable-patches/lockfile.c.patch index 197e81e..6befa64 100644 --- a/stable-patches/lockfile.c.patch +++ b/stable-patches/lockfile.c.patch @@ -1,8 +1,8 @@ diff --git a/lockfile.c b/lockfile.c -index 67082a9..d6977ae 100644 +index 7add2f1..4ae19e2 100644 --- a/lockfile.c +++ b/lockfile.c -@@ -2,10 +2,13 @@ +@@ -2,6 +2,8 @@ * Copyright (c) 2005, Junio C Hamano */ @@ -11,24 +11,45 @@ index 67082a9..d6977ae 100644 #include "git-compat-util.h" #include "abspath.h" #include "gettext.h" - #include "lockfile.h" +@@ -9,6 +11,7 @@ + #include "parse.h" + #include "strbuf.h" + #include "wrapper.h" +#include "environment.h" /* * path = absolute or relative path name -@@ -83,6 +86,15 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, +@@ -168,6 +171,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, + struct strbuf base_path = STRBUF_INIT; + struct strbuf lock_path = STRBUF_INIT; + struct strbuf pid_path = STRBUF_INIT; ++ struct stat st; - strbuf_addstr(&filename, LOCK_SUFFIX); - lk->tempfile = create_tempfile_mode(filename.buf, mode); + strbuf_addstr(&base_path, path); + if (!(flags & LOCK_NO_DEREF)) +@@ -177,8 +181,24 @@ static int lock_file(struct lock_file *lk, const char *path, int flags, + get_pid_path(&pid_path, base_path.buf); + + lk->tempfile = create_tempfile_mode(lock_path.buf, mode); +- if (lk->tempfile) +#ifdef __MVS__ -+ struct stat st; -+ if (lk->tempfile && fstat(lk->tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) { ++ if (lk->tempfile && fstat(lk->tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) ++ { + if (flags & LOCK_TAG_TEXT) + __chgfdccsid(lk->tempfile->fd, utf8_ccsid); + else + __setfdbinary(lk->tempfile->fd); ++ + lk->pid_tempfile = create_lock_pid_file(pid_path.buf, mode); ++ if (lk->pid_tempfile && fstat(lk->pid_tempfile->fd, &st) >= 0 && S_ISREG(st.st_mode)) ++ { ++ if (flags & LOCK_TAG_TEXT) ++ __chgfdccsid(lk->pid_tempfile->fd, utf8_ccsid); ++ else ++ __setfdbinary(lk->pid_tempfile->fd); ++ } + } +#endif - strbuf_release(&filename); - return lk->tempfile ? lk->tempfile->fd : -1; - } + + strbuf_release(&base_path); + strbuf_release(&lock_path); diff --git a/stable-patches/lockfile.h.patch b/stable-patches/lockfile.h.patch index d3ee99f..4c163f0 100644 --- a/stable-patches/lockfile.h.patch +++ b/stable-patches/lockfile.h.patch @@ -1,8 +1,8 @@ diff --git a/lockfile.h b/lockfile.h -index 1bb9926..de6143c 100644 +index e7233f2..efa9a0a 100644 --- a/lockfile.h +++ b/lockfile.h -@@ -148,6 +148,11 @@ struct lock_file { +@@ -165,6 +165,11 @@ extern int lockfile_pid_enabled; */ #define LOCK_REPORT_ON_ERROR 4 diff --git a/stable-patches/object-file.c.patch b/stable-patches/object-file.c.patch index 12a989f..ede1388 100644 --- a/stable-patches/object-file.c.patch +++ b/stable-patches/object-file.c.patch @@ -1,130 +1,15 @@ diff --git a/object-file.c b/object-file.c -index e7e4c33..b64b44b 100644 +index 2acc952..d78fb1d 100644 --- a/object-file.c +++ b/object-file.c -@@ -154,7 +154,7 @@ int stream_object_signature(struct repository *r, const struct object_id *oid) - if (readlen < 0) { - odb_read_stream_close(st); - return -1; -- } -+ } - if (!readlen) - break; - git_hash_update(&c, buf, readlen); -@@ -225,7 +225,7 @@ static void *map_fd(int fd, const char *path, unsigned long *size) - error(_("object file %s is empty"), path); - close(fd); - return NULL; -- } -+ } - map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0); - } - close(fd); -@@ -329,7 +329,7 @@ static void *unpack_loose_rest(git_zstream *stream, - obj_read_unlock(); - status = git_inflate(stream, Z_FINISH); - obj_read_lock(); -- } -+ } - } - - if (status != Z_STREAM_END) { -@@ -393,7 +393,7 @@ static int parse_loose_header(const char *hdr, struct object_info *oi) - break; - hdr++; - size = st_add(st_mult(size, 10), c); -- } -+ } - } - - if (oi->sizep) -@@ -440,12 +440,12 @@ int odb_source_loose_read_object_info(struct odb_source *source, - if ((!oi || !oi->disk_sizep) && (flags & OBJECT_INFO_QUICK)) { - ret = quick_has_loose(source->loose, oid) ? 0 : -1; - goto out; -- } -+ } - - if (stat_loose_object(source->loose, oid, &st, &path) < 0) { - ret = -1; - goto out; -- } -+ } - - if (oi && oi->disk_sizep) - *oi->disk_sizep = st.st_size; -@@ -483,7 +483,7 @@ int odb_source_loose_read_object_info(struct odb_source *source, - if (parse_loose_header(hdr, oi) < 0) { - ret = error(_("unable to parse %s header"), oid_to_hex(oid)); - goto corrupt; -- } -+ } - - if (*oi->typep < 0) - die(_("invalid object type")); -@@ -493,8 +493,8 @@ int odb_source_loose_read_object_info(struct odb_source *source, - if (!*oi->contentp) { - ret = -1; - goto corrupt; -- } - } -+ } - - break; - case ULHR_BAD: -@@ -588,19 +588,19 @@ static int check_collision(const char *source, const char *dest) - if (sz_a < 0) { - ret = error_errno(_("unable to read %s"), source); - goto out; -- } -+ } - - sz_b = read_in_full(fd_dest, buf_dest, sizeof(buf_dest)); - if (sz_b < 0) { - ret = error_errno(_("unable to read %s"), dest); - goto out; -- } -+ } - - if (sz_a != sz_b || memcmp(buf_source, buf_dest, sz_a)) { - ret = error(_("files '%s' and '%s' differ in contents"), - source, dest); - goto out; -- } -+ } - - if ((size_t) sz_a < sizeof(buf_source)) - break; -@@ -668,7 +668,7 @@ int finalize_object_file_flags(struct repository *repo, - unlink_or_warn(tmpfile); - errno = saved_errno; - return error_errno(_("unable to write file %s"), filename); -- } -+ } - if (!(flags & FOF_SKIP_COLLISION_CHECK)) { - ret = check_collision(tmpfile, filename); - if (ret == CHECK_COLLISION_DEST_VANISHED) { -@@ -676,10 +676,10 @@ int finalize_object_file_flags(struct repository *repo, - return error(_("unable to write repeatedly vanishing file %s"), - filename); - goto retry; -- } -+ } - else if (ret) - return -1; -- } -+ } - unlink_or_warn(tmpfile); - } - -@@ -826,11 +826,20 @@ static int create_tmpfile(struct repository *repo, +@@ -858,11 +858,19 @@ static int create_tmpfile(struct repository *repo, struct strbuf *tmp, const char *filename) { int fd, dirlen = directory_size(filename); +- +#ifdef __MVS__ + struct stat st; +#endif - strbuf_reset(tmp); strbuf_add(tmp, filename, dirlen); strbuf_addstr(tmp, "tmp_obj_XXXXXX"); @@ -138,7 +23,7 @@ index e7e4c33..b64b44b 100644 if (fd < 0 && dirlen && errno == ENOENT) { /* * Make sure the directory exists; note that the contents -@@ -848,6 +857,12 @@ static int create_tmpfile(struct repository *repo, +@@ -880,6 +888,12 @@ static int create_tmpfile(struct repository *repo, /* Try again */ strbuf_addstr(tmp, "/tmp_obj_XXXXXX"); fd = git_mkstemp_mode(tmp->buf, 0444); @@ -151,100 +36,20 @@ index e7e4c33..b64b44b 100644 } return fd; } -@@ -1074,7 +1089,7 @@ int odb_source_loose_write_stream(struct odb_source *source, - /* All data has been read. */ - if (in_stream->is_finished) - flush = 1; -- } -+ } - ret = write_loose_object_common(source, &c, &compat_c, &stream, flush, in0, fd, - compressed, sizeof(compressed)); - /* -@@ -1120,7 +1135,7 @@ int odb_source_loose_write_stream(struct odb_source *source, - err = error_errno(_("unable to create directory %s"), dir.buf); - strbuf_release(&dir); - goto cleanup; -- } -+ } - strbuf_release(&dir); - } - -@@ -1158,7 +1173,7 @@ int odb_source_loose_write_object(struct odb_source *source, - hash_object_file(compat, converted.buf, converted.len, - type, &compat_oid); - strbuf_release(&converted); -- } -+ } - } - - /* Normally if we have it in the pack then we do not bother writing -@@ -1243,11 +1258,12 @@ static int index_mem(struct index_state *istate, +@@ -1276,8 +1290,10 @@ static int index_mem(struct index_state *istate, * Convert blobs to git internal format */ if ((type == OBJ_BLOB) && path) { - if (convert_to_git(istate, path, buf, size, &nbuf, - get_conv_flags(flags))) { -+ int ret = convert_to_git(istate, path, buf, size, &nbuf, ++ ret = convert_to_git(istate, path, buf, size, &nbuf, + get_conv_flags(flags)); -+ if (ret > 0) { ++ if(ret > 0) ++ { buf = nbuf.buf; size = nbuf.len; -- } -+ } - } - if (flags & INDEX_FORMAT_CHECK) { - struct fsck_options opts = FSCK_OPTIONS_DEFAULT; -@@ -1426,11 +1442,11 @@ static int stream_blob_to_pack(struct transaction_packfile *state, - if (hsize) - git_hash_update(ctx, ibuf, hsize); - *already_hashed_to = offset; -- } -+ } - s.next_in = ibuf; - s.avail_in = rsize; - size -= rsize; -- } -+ } - - status = git_deflate(&s, size ? 0 : Z_FINISH); - -@@ -1444,14 +1460,14 @@ static int stream_blob_to_pack(struct transaction_packfile *state, - pack_size_limit_cfg < state->offset + written) { - git_deflate_abort(&s); - return -1; -- } -+ } - - hashwrite(state->f, obuf, written); - state->offset += written; -- } -+ } - s.next_out = obuf; - s.avail_out = sizeof(obuf); -- } -+ } - - switch (status) { - case Z_OK: -@@ -1460,7 +1476,7 @@ static int stream_blob_to_pack(struct transaction_packfile *state, - continue; - default: - die("unexpected deflate failure: %d", status); -- } -+ } - } - git_deflate_end(&s); - return 0; -@@ -1572,7 +1588,7 @@ static int index_blob_packfile_transaction(struct odb_transaction *transaction, - hashfile_checkpoint(state->f, &checkpoint); - idx->offset = state->offset; - crc32_begin(state->f); -- } -+ } - if (!stream_blob_to_pack(state, &ctx, &already_hashed_to, - fd, size, path, flags)) - break; -@@ -1649,12 +1665,21 @@ int index_path(struct index_state *istate, struct object_id *oid, + } +@@ -1720,12 +1736,21 @@ int index_path(struct index_state *istate, struct object_id *oid, int fd; struct strbuf sb = STRBUF_INIT; int rc = 0; @@ -254,7 +59,7 @@ index e7e4c33..b64b44b 100644 switch (st->st_mode & S_IFMT) { case S_IFREG: +#ifdef __MVS__ -+ validate_codeset(istate, path, &autocvtToASCII); ++ validate_codeset(istate, path, &autocvtToASCII); +#endif fd = open(path, O_RDONLY); if (fd < 0) @@ -266,46 +71,3 @@ index e7e4c33..b64b44b 100644 if (index_fd(istate, oid, fd, st, OBJ_BLOB, path, flags) < 0) return error(_("%s: failed to insert into database"), path); -@@ -1745,15 +1770,15 @@ static int for_each_file_in_obj_subdir(unsigned int subdir_nr, - r = obj_cb(&oid, path->buf, data); - if (r) - break; -- } -- continue; - } -+ continue; -+ } - - if (cruft_cb) { - r = cruft_cb(de->d_name, path->buf, data); - if (r) - break; -- } -+ } - } - closedir(dir); - -@@ -1967,7 +1992,7 @@ int read_loose_object(struct repository *repo, - if (!*contents) { - error(_("unable to unpack contents of %s"), path); - goto out_inflate; -- } -+ } - hash_object_file(repo->hash_algo, - *contents, *size, - *oi->typep, real_oid); -@@ -2082,12 +2107,12 @@ static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t - git_inflate_end(&st->z); - st->z_state = ODB_LOOSE_READ_STREAM_DONE; - break; -- } -+ } - if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) { - git_inflate_end(&st->z); - st->z_state = ODB_LOOSE_READ_STREAM_ERROR; - return -1; -- } -+ } - } - return total_read; - } diff --git a/stable-patches/odb.c.patch b/stable-patches/odb.c.patch index 825027f..4d5c150 100644 --- a/stable-patches/odb.c.patch +++ b/stable-patches/odb.c.patch @@ -1,14 +1,9 @@ diff --git a/odb.c b/odb.c -index ac70b6a..699e986 100644 +index 9b28fe2..404d706 100644 --- a/odb.c +++ b/odb.c -@@ -66,9 +66,13 @@ static const struct cached_object *find_cached_object(struct object_database *ob - } - - int odb_mkstemp(struct object_database *odb, -- struct strbuf *temp_filename, const char *pattern) -+ struct strbuf *temp_filename, -+ const char *pattern) +@@ -69,6 +69,9 @@ int odb_mkstemp(struct object_database *odb, + struct strbuf *temp_filename, const char *pattern) { int fd; +#ifdef __MVS__ @@ -17,7 +12,7 @@ index ac70b6a..699e986 100644 /* * we let the umask do its job, don't try to be more * restrictive except to remove write permission. -@@ -76,6 +80,12 @@ int odb_mkstemp(struct object_database *odb, +@@ -76,6 +79,12 @@ int odb_mkstemp(struct object_database *odb, int mode = 0444; repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); fd = git_mkstemp_mode(temp_filename->buf, mode); @@ -30,7 +25,7 @@ index ac70b6a..699e986 100644 if (0 <= fd) return fd; -@@ -83,9 +93,17 @@ int odb_mkstemp(struct object_database *odb, +@@ -83,7 +92,14 @@ int odb_mkstemp(struct object_database *odb, /* some mkstemp implementations erase temp_filename on failure */ repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); safe_create_leading_directories(odb->repo, temp_filename->buf); @@ -45,194 +40,4 @@ index ac70b6a..699e986 100644 + return fd; } -+ /* - * Return non-zero iff the path is usable as an alternate object database. - */ -@@ -152,18 +170,18 @@ static void parse_alternates(const char *string, - if (*string == '#') { - /* comment; consume up to next separator */ - end = strchrnul(string, sep); -- } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { -+ } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { - /* - * quoted path; unquote_c_style has copied the - * data for us and set "end". Broken quoting (e.g., - * an entry that doesn't end with a quote) falls - * back to the unquoted case below. - */ -- } else { -+ } else { - /* normal, unquoted path */ - end = strchrnul(string, sep); - strbuf_add(&buf, string, end - string); -- } -+ } - - if (*end) - end++; -@@ -175,7 +193,7 @@ static void parse_alternates(const char *string, - if (!is_absolute_path(buf.buf) && relative_base) { - strbuf_realpath(&pathbuf, relative_base, 1); - strbuf_addch(&pathbuf, '/'); -- } -+ } - strbuf_addbuf(&pathbuf, &buf); - - strbuf_reset(&buf); -@@ -183,7 +201,7 @@ static void parse_alternates(const char *string, - error(_("unable to normalize alternate object path: %s"), - pathbuf.buf); - continue; -- } -+ } - - /* - * The trailing slash after the directory name is given by -@@ -296,9 +314,9 @@ static int odb_source_write_alternate(struct odb_source *source, - if (!strcmp(alternate, line.buf)) { - found = 1; - break; -- } -- fprintf_or_die(out, "%s\n", line.buf); - } -+ fprintf_or_die(out, "%s\n", line.buf); -+ } - - strbuf_release(&line); - fclose(in); -@@ -314,7 +332,7 @@ static int odb_source_write_alternate(struct odb_source *source, - if (commit_lock_file(&lock)) { - ret = error_errno(_("unable to move new alternates file into place")); - goto out; -- } -+ } - } - - ret = 0; -@@ -433,7 +451,7 @@ char *compute_alternate_path(const char *path, struct strbuf *err) - "checkout is not supported yet."), - path); - goto out; -- } -+ } - - strbuf_addf(err, _("reference repository '%s' is not a " - "local repository."), path); -@@ -517,7 +535,7 @@ static void fill_alternate_refs_command(struct repository *repo, - if (!repo_config_get_value(repo, "core.alternateRefsPrefixes", &value)) { - strvec_push(&cmd->args, "--"); - strvec_split(&cmd->args, value); -- } -+ } - } - - strvec_pushv(&cmd->env, (const char **)local_repo_env); -@@ -547,7 +565,7 @@ static void read_alternate_refs(struct repository *repo, - warning(_("invalid line while parsing alternate refs: %s"), - line.buf); - break; -- } -+ } - - cb(&oid, payload); - } -@@ -703,7 +721,7 @@ static int do_oid_object_info_extended(struct object_database *odb, - if (oi->contentp) - *oi->contentp = xmemdupz(co->buf, co->size); - oi->whence = OI_CACHED; -- } -+ } - return 0; - } - -@@ -717,7 +735,7 @@ static int do_oid_object_info_extended(struct object_database *odb, - if (!packfile_store_read_object_info(source->packfiles, real, oi, flags) || - !odb_source_loose_read_object_info(source, real, oi, flags)) - return 0; -- } -+ } - - /* Not a loose object; someone else may have just packed it. */ - if (!(flags & OBJECT_INFO_QUICK)) { -@@ -725,7 +743,7 @@ static int do_oid_object_info_extended(struct object_database *odb, - for (source = odb->sources; source; source = source->next) - if (!packfile_store_read_object_info(source->packfiles, real, oi, flags)) - return 0; -- } -+ } - - /* - * This might be an attempt at accessing a submodule object as -@@ -744,7 +762,7 @@ static int do_oid_object_info_extended(struct object_database *odb, - promisor_remote_get_direct(odb->repo, real, 1); - already_retried = 1; - continue; -- } -+ } - - if (flags & OBJECT_INFO_DIE_IF_CORRUPT) { - const struct packed_git *p; -@@ -754,7 +772,7 @@ static int do_oid_object_info_extended(struct object_database *odb, - if ((p = has_packed_and_bad(odb->repo, real))) - die(_("packed object %s (stored in %s) is corrupt"), - oid_to_hex(real), p->pack_name); -- } -+ } - return -1; - } - } -@@ -792,7 +810,7 @@ static int oid_object_info_convert(struct repository *r, - new_oi.contentp = &content; - new_oi.sizep = &size; - new_oi.typep = &type; -- } -+ } - oi = &new_oi; - } - -@@ -814,7 +832,7 @@ static int oid_object_info_convert(struct repository *r, - return -1; - size = outbuf.len; - content = strbuf_detach(&outbuf, NULL); -- } -+ } - if (input_oi->sizep) - *input_oi->sizep = size; - if (input_oi->contentp) -@@ -832,7 +850,7 @@ static int oid_object_info_convert(struct repository *r, - oid_to_hex(&delta_base_oid), - input_algo->name); - return -1; -- } -+ } - } - input_oi->whence = new_oi.whence; - input_oi->u = new_oi.u; -@@ -938,7 +956,7 @@ void *odb_read_object_peeled(struct object_database *odb, - if (actual_oid_return) - oidcpy(actual_oid_return, &actual_oid); - return buffer; -- } -+ } - /* Handle references */ - else if (type == OBJ_COMMIT) - ref_type = "tree "; -@@ -947,7 +965,7 @@ void *odb_read_object_peeled(struct object_database *odb, - else { - free(buffer); - return NULL; -- } -+ } - ref_length = strlen(ref_type); - - if (ref_length + odb->repo->hash_algo->hexsz > isize || -@@ -956,7 +974,7 @@ void *odb_read_object_peeled(struct object_database *odb, - odb->repo->hash_algo)) { - free(buffer); - return NULL; -- } -+ } - free(buffer); - /* Now we have the ID of the referred-to object in - * actual_oid. Check again. */ diff --git a/stable-patches/read-cache-ll.h.patch b/stable-patches/read-cache-ll.h.patch index 80fd8bc..fad7b4c 100644 --- a/stable-patches/read-cache-ll.h.patch +++ b/stable-patches/read-cache-ll.h.patch @@ -1,8 +1,8 @@ diff --git a/read-cache-ll.h b/read-cache-ll.h -index 9a1a7ed..a99eef7 100644 +index 2c8b4b2..fd3b627 100644 --- a/read-cache-ll.h +++ b/read-cache-ll.h -@@ -466,6 +466,10 @@ struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry +@@ -474,6 +474,10 @@ struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry void set_alternate_index_output(const char *); diff --git a/stable-patches/read-cache.c.patch b/stable-patches/read-cache.c.patch index e197cbb..08fa71a 100644 --- a/stable-patches/read-cache.c.patch +++ b/stable-patches/read-cache.c.patch @@ -1,8 +1,8 @@ diff --git a/read-cache.c b/read-cache.c -index 0c07c3a..2c942a3 100644 +index 38a04b8..0eb0109 100644 --- a/read-cache.c +++ b/read-cache.c -@@ -234,6 +234,9 @@ static int ce_compare_data(struct index_state *istate, +@@ -237,6 +237,9 @@ static int ce_compare_data(struct index_state *istate, int fd = git_open_cloexec(ce->name, O_RDONLY); if (fd >= 0) { diff --git a/stable-patches/repository.c.patch b/stable-patches/repository.c.patch index 75a2e70..27e59f1 100644 --- a/stable-patches/repository.c.patch +++ b/stable-patches/repository.c.patch @@ -1,8 +1,8 @@ diff --git a/repository.c b/repository.c -index c7e7521..c42709f 100644 +index 9e5537f..841d000 100644 --- a/repository.c +++ b/repository.c -@@ -325,7 +325,7 @@ int repo_submodule_init(struct repository *subrepo, +@@ -352,7 +352,7 @@ int repo_submodule_init(struct repository *subrepo, if (!sub) { ret = -1; goto out; @@ -11,7 +11,7 @@ index c7e7521..c42709f 100644 strbuf_reset(&gitdir); submodule_name_to_gitdir(&gitdir, superproject, sub->name); -@@ -333,7 +333,7 @@ int repo_submodule_init(struct repository *subrepo, +@@ -360,7 +360,7 @@ int repo_submodule_init(struct repository *subrepo, if (repo_init(subrepo, gitdir.buf, NULL)) { ret = -1; goto out; @@ -20,7 +20,7 @@ index c7e7521..c42709f 100644 } subrepo->submodule_prefix = xstrfmt("%s%s/", -@@ -446,7 +446,16 @@ int repo_hold_locked_index(struct repository *repo, +@@ -479,7 +479,16 @@ int repo_hold_locked_index(struct repository *repo, struct lock_file *lf, int flags) { diff --git a/stable-patches/run-command.c.patch b/stable-patches/run-command.c.patch index 9c8add2..f6e6340 100644 --- a/stable-patches/run-command.c.patch +++ b/stable-patches/run-command.c.patch @@ -1,8 +1,8 @@ diff --git a/run-command.c b/run-command.c -index e3e0247..ee3447b 100644 +index c146a56..680ed4c 100644 --- a/run-command.c +++ b/run-command.c -@@ -19,6 +19,10 @@ +@@ -18,6 +18,10 @@ #include "packfile.h" #include "compat/nonblock.h" @@ -13,7 +13,7 @@ index e3e0247..ee3447b 100644 void child_process_init(struct child_process *child) { struct child_process blank = CHILD_PROCESS_INIT; -@@ -695,6 +699,10 @@ int start_command(struct child_process *cmd) +@@ -694,6 +698,10 @@ int start_command(struct child_process *cmd) str = "standard input"; goto fail_pipe; } @@ -24,7 +24,7 @@ index e3e0247..ee3447b 100644 cmd->in = fdin[1]; } -@@ -711,6 +719,10 @@ int start_command(struct child_process *cmd) +@@ -710,6 +718,10 @@ int start_command(struct child_process *cmd) str = "standard output"; goto fail_pipe; } @@ -35,7 +35,7 @@ index e3e0247..ee3447b 100644 cmd->out = fdout[0]; } -@@ -727,13 +739,12 @@ int start_command(struct child_process *cmd) +@@ -726,13 +738,12 @@ int start_command(struct child_process *cmd) else if (cmd->out) close(cmd->out); str = "standard error"; @@ -54,7 +54,7 @@ index e3e0247..ee3447b 100644 cmd->err = fderr[0]; } -@@ -953,6 +964,7 @@ int start_command(struct child_process *cmd) +@@ -952,6 +963,7 @@ int start_command(struct child_process *cmd) #endif if (cmd->pid < 0) { @@ -62,7 +62,7 @@ index e3e0247..ee3447b 100644 trace2_child_exit(cmd, -1); if (need_in) -@@ -1162,6 +1174,10 @@ int start_async(struct async *async) +@@ -1161,6 +1173,10 @@ int start_async(struct async *async) close(async->out); return error_errno("cannot create pipe"); } @@ -73,7 +73,7 @@ index e3e0247..ee3447b 100644 async->in = fdin[1]; } -@@ -1174,6 +1190,10 @@ int start_async(struct async *async) +@@ -1173,6 +1189,10 @@ int start_async(struct async *async) close(async->in); return error_errno("cannot create pipe"); } diff --git a/stable-patches/strbuf.c.patch b/stable-patches/strbuf.c.patch deleted file mode 100644 index e69de29..0000000 diff --git a/stable-patches/t-meson.build.patch b/stable-patches/t-meson.build.patch index 9c968a3..f2508b9 100644 --- a/stable-patches/t-meson.build.patch +++ b/stable-patches/t-meson.build.patch @@ -1,8 +1,8 @@ diff --git a/t/meson.build b/t/meson.build -index 459c52a..60c99db 100644 +index 7528e5c..967776d 100644 --- a/t/meson.build +++ b/t/meson.build -@@ -118,6 +118,7 @@ integration_tests = [ +@@ -121,6 +121,7 @@ integration_tests = [ 't0071-sort.sh', 't0080-unit-test-output.sh', 't0081-find-pack.sh', diff --git a/stable-patches/test-lib.sh.patch b/stable-patches/test-lib.sh.patch index a521810..6405001 100644 --- a/stable-patches/test-lib.sh.patch +++ b/stable-patches/test-lib.sh.patch @@ -1,8 +1,8 @@ -diff --git i/t/test-lib.sh w/t/test-lib.sh -index 92d0db1..2c32678 100644 ---- i/t/test-lib.sh -+++ w/t/test-lib.sh -@@ -1576,7 +1576,7 @@ fi +diff --git a/t/test-lib.sh b/t/test-lib.sh +index 70fd3e9..248504b 100644 +--- a/t/test-lib.sh ++++ b/t/test-lib.sh +@@ -1593,7 +1593,7 @@ fi # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). diff --git a/stable-patches/utf8.c.patch b/stable-patches/utf8.c.patch index 770c420..a06190d 100644 --- a/stable-patches/utf8.c.patch +++ b/stable-patches/utf8.c.patch @@ -1,5 +1,5 @@ diff --git a/utf8.c b/utf8.c -index 96460cc..e99160a 100644 +index 96460cc..2a15cf7 100644 --- a/utf8.c +++ b/utf8.c @@ -1,6 +1,8 @@ @@ -11,10 +11,10 @@ index 96460cc..e99160a 100644 #include "strbuf.h" #include "utf8.h" -@@ -568,6 +570,20 @@ char *reencode_string_len(const char *in, size_t insz, +@@ -567,6 +569,20 @@ char *reencode_string_len(const char *in, size_t insz, + { iconv_t conv; char *out; - const char *bom_str = NULL; + +#ifdef __MVS__ + if (utf8_ccsid == 819) { @@ -29,10 +29,10 @@ index 96460cc..e99160a 100644 + } + } +#endif + const char *bom_str = NULL; size_t bom_len = 0; - if (!in_encoding) -@@ -837,3 +853,116 @@ void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int wid +@@ -837,3 +853,154 @@ void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int wid } else if (position == ALIGN_RIGHT) strbuf_addf(buf, "%*s", width + utf8_compensation, s); } @@ -43,6 +43,20 @@ index 96460cc..e99160a 100644 +{ + iconv_t conv; + char *out; ++ ++#ifdef __MVS__ ++ if (utf8_ccsid == 819) { ++ /* HACK: For backwards compat UTF CCSID=819, ISO8859-1 really means utf-8 in the z/OS world */ ++ if (in_encoding && !strcasecmp("ISO8859-1", in_encoding)) { ++ in_encoding = "UTF-8"; ++ out_encoding = "UTF-8"; ++ } ++ if (out_encoding && !strcasecmp("ISO8859-1", out_encoding)) { ++ in_encoding = "UTF-8"; ++ out_encoding = "UTF-8"; ++ } ++ } ++#endif + const char *bom_str = NULL; + size_t bom_len = 0; + char *out_encoding_translit; @@ -149,3 +163,27 @@ index 96460cc..e99160a 100644 + *line_out = line; + *col_out = col; +} ++ ++void find_first_non_ascii(const char *src, size_t src_len, ++ size_t *line_out, size_t *col_out, ++ unsigned char *bad_char_out) ++{ ++ size_t line = 1, col = 0; ++ unsigned char bad_char = 0; ++ for (size_t i = 0; i < src_len; i++) { ++ if (src[i] == '\n' || is_ebcdic_newline(src[i])) { ++ line++; ++ col = 0; ++ } else { ++ col++; ++ } ++ /* Try to find the first character that iconv would reject (non-ASCII) */ ++ if ((unsigned char)src[i] > 0x7F) { ++ bad_char = (unsigned char)src[i]; ++ break; ++ } ++ } ++ *line_out = line; ++ *col_out = col; ++ *bad_char_out = bad_char; ++}