diff options
-rw-r--r-- | findutils/xargs.c | 105 |
1 files changed, 103 insertions, 2 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index a3a15bfbc..f0abf1a23 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -336,6 +336,8 @@ static int xargs_exec(void) | |||
336 | #endif | 336 | #endif |
337 | 337 | ||
338 | #if ENABLE_PLATFORM_MINGW32 | 338 | #if ENABLE_PLATFORM_MINGW32 |
339 | /* Any change to the logic for NOFORK applets must be duplicated | ||
340 | * in xargs_main() below. */ | ||
339 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 341 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
340 | if (G.max_procs == 1) { | 342 | if (G.max_procs == 1) { |
341 | # endif | 343 | # endif |
@@ -720,6 +722,20 @@ static int xargs_ask_confirmation(void) | |||
720 | # define xargs_ask_confirmation() 1 | 722 | # define xargs_ask_confirmation() 1 |
721 | #endif | 723 | #endif |
722 | 724 | ||
725 | #if ENABLE_PLATFORM_MINGW32 | ||
726 | // Maximum command length (less a few bytes) | ||
727 | # define WIN32_MAX_CHARS (32750) | ||
728 | |||
729 | static size_t quote_len(const char *arg) | ||
730 | { | ||
731 | char *s = quote_arg(arg); | ||
732 | size_t len = strlen(s); | ||
733 | |||
734 | free(s); | ||
735 | return len; | ||
736 | } | ||
737 | #endif | ||
738 | |||
723 | //usage:#define xargs_trivial_usage | 739 | //usage:#define xargs_trivial_usage |
724 | //usage: "[OPTIONS] [PROG ARGS]" | 740 | //usage: "[OPTIONS] [PROG ARGS]" |
725 | //usage:#define xargs_full_usage "\n\n" | 741 | //usage:#define xargs_full_usage "\n\n" |
@@ -765,6 +781,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
765 | unsigned opt; | 781 | unsigned opt; |
766 | int n_max_chars; | 782 | int n_max_chars; |
767 | int n_max_arg; | 783 | int n_max_arg; |
784 | #if ENABLE_PLATFORM_MINGW32 | ||
785 | int delta = 0; | ||
786 | int quote = TRUE; | ||
787 | char *old_buf = NULL; | ||
788 | #endif | ||
768 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ | 789 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ |
769 | || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR | 790 | || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR |
770 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; | 791 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; |
@@ -820,6 +841,24 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
820 | //argc++; | 841 | //argc++; |
821 | } | 842 | } |
822 | 843 | ||
844 | #if ENABLE_PLATFORM_MINGW32 | ||
845 | /* On Windows the command line may be expanded by the need to quote | ||
846 | * arguments, but not if the command is a NOFORK applet. If the rules | ||
847 | * to detect this situation change xargs_exec() above will also need | ||
848 | * to be updated. */ | ||
849 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
850 | if (G.max_procs == 1) | ||
851 | # endif | ||
852 | { | ||
853 | # if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) | ||
854 | int applet = find_applet_by_name(argv[0]); | ||
855 | if (applet >= 0 && APPLET_IS_NOFORK(applet)) { | ||
856 | quote = FALSE; | ||
857 | } | ||
858 | } | ||
859 | # endif | ||
860 | #endif | ||
861 | |||
823 | /* | 862 | /* |
824 | * The Open Group Base Specifications Issue 6: | 863 | * The Open Group Base Specifications Issue 6: |
825 | * "The xargs utility shall limit the command line length such that | 864 | * "The xargs utility shall limit the command line length such that |
@@ -844,7 +883,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
844 | { | 883 | { |
845 | size_t n_chars = 0; | 884 | size_t n_chars = 0; |
846 | for (i = 0; argv[i]; i++) { | 885 | for (i = 0; argv[i]; i++) { |
847 | n_chars += strlen(argv[i]) + 1; | 886 | #if ENABLE_PLATFORM_MINGW32 |
887 | if (quote) | ||
888 | n_chars += quote_len(argv[i]) + 1; | ||
889 | else | ||
890 | #endif | ||
891 | n_chars += strlen(argv[i]) + 1; | ||
848 | } | 892 | } |
849 | n_max_chars -= n_chars; | 893 | n_max_chars -= n_chars; |
850 | } | 894 | } |
@@ -903,11 +947,36 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
903 | initial_idx = G.idx; | 947 | initial_idx = G.idx; |
904 | while (1) { | 948 | while (1) { |
905 | char *rem; | 949 | char *rem; |
950 | #if ENABLE_PLATFORM_MINGW32 | ||
951 | char **args; | ||
952 | char **tail = NULL; | ||
953 | char *saved_arg = NULL; | ||
954 | size_t n_chars; | ||
955 | #endif | ||
906 | 956 | ||
907 | G.idx = initial_idx; | 957 | G.idx = initial_idx IF_PLATFORM_MINGW32(+ delta); |
908 | rem = read_args(n_max_chars, n_max_arg, buf); | 958 | rem = read_args(n_max_chars, n_max_arg, buf); |
909 | store_param(NULL); | 959 | store_param(NULL); |
910 | 960 | ||
961 | #if ENABLE_PLATFORM_MINGW32 | ||
962 | /* Check if quoting expands the command line. If it does we | ||
963 | * truncate args[] and preserve the tail for processing later. */ | ||
964 | args = G.args; | ||
965 | if (quote) { | ||
966 | skip_read: | ||
967 | n_chars = 0; | ||
968 | for (i = initial_idx; args[i]; i++) { | ||
969 | n_chars += quote_len(args[i]) + 1; | ||
970 | if (n_chars > WIN32_MAX_CHARS) { | ||
971 | tail = args + i; | ||
972 | saved_arg = *tail; | ||
973 | *tail = NULL; | ||
974 | break; | ||
975 | } | ||
976 | } | ||
977 | } | ||
978 | #endif | ||
979 | |||
911 | if (!G.args[initial_idx]) { /* not even one ARG was added? */ | 980 | if (!G.args[initial_idx]) { /* not even one ARG was added? */ |
912 | if (*rem != '\0') | 981 | if (*rem != '\0') |
913 | bb_simple_error_msg_and_die("argument line too long"); | 982 | bb_simple_error_msg_and_die("argument line too long"); |
@@ -918,7 +987,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
918 | 987 | ||
919 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { | 988 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { |
920 | const char *fmt = " %s" + 1; | 989 | const char *fmt = " %s" + 1; |
990 | #if !ENABLE_PLATFORM_MINGW32 | ||
921 | char **args = G.args; | 991 | char **args = G.args; |
992 | #endif | ||
922 | for (i = 0; args[i]; i++) { | 993 | for (i = 0; args[i]; i++) { |
923 | fprintf(stderr, fmt, args[i]); | 994 | fprintf(stderr, fmt, args[i]); |
924 | fmt = " %s"; | 995 | fmt = " %s"; |
@@ -932,6 +1003,33 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
932 | break; /* G.xargs_exitcode is set by xargs_exec() */ | 1003 | break; /* G.xargs_exitcode is set by xargs_exec() */ |
933 | } | 1004 | } |
934 | 1005 | ||
1006 | #if ENABLE_PLATFORM_MINGW32 | ||
1007 | delta = 0; | ||
1008 | if (quote && tail) { | ||
1009 | /* The command line was truncated. Preload args[] with | ||
1010 | * the tail we saved earlier. */ | ||
1011 | *tail = saved_arg; | ||
1012 | n_chars = 0; | ||
1013 | for (i = 0; tail[i]; i++) { | ||
1014 | args[initial_idx + i] = tail[i]; | ||
1015 | n_chars += quote_len(tail[i]) + 1; | ||
1016 | } | ||
1017 | args[initial_idx + i] = NULL; | ||
1018 | delta = i; | ||
1019 | |||
1020 | /* The command line still overflows after quoting. | ||
1021 | * Truncate the new args[] and exec it. */ | ||
1022 | if (n_chars > WIN32_MAX_CHARS) | ||
1023 | goto skip_read; | ||
1024 | |||
1025 | /* The first elements of args[] point to strings in the | ||
1026 | * current buf, so we need to preserve it. Allocate a | ||
1027 | * new buf for future use. */ | ||
1028 | free(old_buf); | ||
1029 | old_buf = buf; | ||
1030 | buf = xzalloc(n_max_chars + 1); | ||
1031 | } | ||
1032 | #endif | ||
935 | overlapping_strcpy(buf, rem); | 1033 | overlapping_strcpy(buf, rem); |
936 | } /* while */ | 1034 | } /* while */ |
937 | 1035 | ||
@@ -939,6 +1037,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
939 | free(G.args); | 1037 | free(G.args); |
940 | free(buf); | 1038 | free(buf); |
941 | } | 1039 | } |
1040 | #if ENABLE_FEATURE_CLEAN_UP && ENABLE_PLATFORM_MINGW32 | ||
1041 | free(old_buf); | ||
1042 | #endif | ||
942 | 1043 | ||
943 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 1044 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
944 | G.max_procs = 0; | 1045 | G.max_procs = 0; |