aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.src24
-rw-r--r--libbb/Kbuild.src51
-rw-r--r--libbb/appletlib.c335
-rw-r--r--libbb/bb_getgroups.c8
-rw-r--r--libbb/bitops.c128
-rw-r--r--libbb/compare_string_array.c41
-rw-r--r--libbb/concat_path_file.c6
-rw-r--r--libbb/const_hack.c21
-rw-r--r--libbb/copy_file.c6
-rw-r--r--libbb/dump.c46
-rw-r--r--libbb/executable.c22
-rw-r--r--libbb/find_mount_point.c31
-rw-r--r--libbb/find_pid_by_name.c6
-rw-r--r--libbb/get_last_path_component.c41
-rw-r--r--libbb/get_line_from_file.c18
-rw-r--r--libbb/getopt32.c4
-rw-r--r--libbb/hash_hmac.c154
-rw-r--r--libbb/hash_md5_sha.c78
-rw-r--r--libbb/hash_sha256_block.c19
-rw-r--r--libbb/hash_sha256_hwaccel_x86-32.S218
-rw-r--r--libbb/hash_sha256_hwaccel_x86-64.S218
-rw-r--r--libbb/herror_msg.c4
-rw-r--r--libbb/human_readable.c6
-rw-r--r--libbb/inode_hash.c5
-rw-r--r--libbb/last_char_is.c11
-rw-r--r--libbb/lineedit.c364
-rw-r--r--libbb/make_directory.c8
-rw-r--r--libbb/messages.c22
-rw-r--r--libbb/mode_string.c2
-rw-r--r--libbb/parse_config.c9
-rw-r--r--libbb/perror_msg.c4
-rw-r--r--libbb/poll_with_signals.c48
-rw-r--r--libbb/printable_string.c2
-rw-r--r--libbb/procps.c3
-rw-r--r--libbb/pw_ascii64.c91
-rw-r--r--libbb/pw_encrypt.c113
-rw-r--r--libbb/pw_encrypt_des.c88
-rw-r--r--libbb/pw_encrypt_md5.c4
-rw-r--r--libbb/pw_encrypt_sha.c5
-rw-r--r--libbb/pw_encrypt_yes.c24
-rw-r--r--libbb/read_key.c30
-rw-r--r--libbb/read_printf.c5
-rw-r--r--libbb/signals.c2
-rw-r--r--libbb/time.c9
-rw-r--r--libbb/u_signal_names.c11
-rw-r--r--libbb/unicode.c13
-rw-r--r--libbb/verror_msg.c6
-rw-r--r--libbb/vfork_daemon_rexec.c6
-rw-r--r--libbb/wcwidth_alt.c506
-rw-r--r--libbb/xatonum_template.c5
-rw-r--r--libbb/xconnect.c14
-rw-r--r--libbb/xfuncs.c16
-rw-r--r--libbb/xfuncs_printf.c14
-rw-r--r--libbb/xreadlink.c45
-rw-r--r--libbb/yescrypt/Kbuild.src9
-rw-r--r--libbb/yescrypt/PARAMETERS196
-rw-r--r--libbb/yescrypt/README4
-rw-r--r--libbb/yescrypt/alg-sha256.c86
-rw-r--r--libbb/yescrypt/alg-yescrypt-common.c408
-rw-r--r--libbb/yescrypt/alg-yescrypt-kdf.c1212
-rw-r--r--libbb/yescrypt/alg-yescrypt.h247
-rw-r--r--libbb/yescrypt/y.c16
62 files changed, 4680 insertions, 468 deletions
diff --git a/libbb/Config.src b/libbb/Config.src
index b980f19a9..eff327c2a 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -37,6 +37,14 @@ config PASSWORD_MINLEN
37 help 37 help
38 Minimum allowable password length. 38 Minimum allowable password length.
39 39
40config FEATURE_USE_CNG_API
41 bool "Use the Windows CNG API for checksums (Windows 10+ only)"
42 default n
43 depends on PLATFORM_MINGW32
44 help
45 Use the in-built Windows CNG API for checksums.
46 This reduces code size, but is only supported on Windows 10+.
47
40config MD5_SMALL 48config MD5_SMALL
41 int "MD5: Trade bytes for speed (0:fast, 3:slow)" 49 int "MD5: Trade bytes for speed (0:fast, 3:slow)"
42 default 1 # all "fast or small" options default to small 50 default 1 # all "fast or small" options default to small
@@ -67,6 +75,7 @@ config SHA1_SMALL
67config SHA1_HWACCEL 75config SHA1_HWACCEL
68 bool "SHA1: Use hardware accelerated instructions if possible" 76 bool "SHA1: Use hardware accelerated instructions if possible"
69 default y 77 default y
78 depends on !FEATURE_USE_CNG_API
70 help 79 help
71 On x86, this adds ~590 bytes of code. Throughput 80 On x86, this adds ~590 bytes of code. Throughput
72 is about twice as fast as fully-unrolled generic code. 81 is about twice as fast as fully-unrolled generic code.
@@ -74,6 +83,7 @@ config SHA1_HWACCEL
74config SHA256_HWACCEL 83config SHA256_HWACCEL
75 bool "SHA256: Use hardware accelerated instructions if possible" 84 bool "SHA256: Use hardware accelerated instructions if possible"
76 default y 85 default y
86 depends on !FEATURE_USE_CNG_API
77 help 87 help
78 On x86, this adds ~1k bytes of code. 88 On x86, this adds ~1k bytes of code.
79 89
@@ -182,12 +192,22 @@ config FEATURE_EDITING_VI
182config FEATURE_EDITING_HISTORY 192config FEATURE_EDITING_HISTORY
183 int "History size" 193 int "History size"
184 # Don't allow way too big values here, code uses fixed "char *history[N]" struct member 194 # Don't allow way too big values here, code uses fixed "char *history[N]" struct member
185 range 0 9999 195 range 0 2000
186 default 255 196 default 200
187 depends on FEATURE_EDITING 197 depends on FEATURE_EDITING
188 help 198 help
189 Specify command history size (0 - disable). 199 Specify command history size (0 - disable).
190 200
201config FEATURE_EDITING_HISTORY_DEFAULT
202 int "Default history size"
203 range 0 FEATURE_EDITING_HISTORY
204 default 255
205 depends on PLATFORM_MINGW32 && FEATURE_EDITING && FEATURE_SH_HISTFILESIZE
206 help
207 Specify default command history size. This may be smaller than
208 FEATURE_EDITING_HISTORY, in which case the user may increase
209 the history size by setting HISTFILESIZE.
210
191config FEATURE_EDITING_SAVEHISTORY 211config FEATURE_EDITING_SAVEHISTORY
192 bool "History saving" 212 bool "History saving"
193 default y 213 default y
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index cb8d2c2ec..32fde90e6 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -10,17 +10,14 @@ lib-y:=
10 10
11INSERT 11INSERT
12 12
13lib-y += alloc_affinity.o
14lib-y += appletlib.o 13lib-y += appletlib.o
15lib-y += ask_confirmation.o 14lib-y += ask_confirmation.o
16lib-y += bb_askpass.o
17lib-y += bb_bswap_64.o 15lib-y += bb_bswap_64.o
18lib-y += bb_do_delay.o 16lib-y += bb_do_delay.o
19lib-y += bb_pwd.o 17lib-y += bb_pwd.o
20lib-y += bb_qsort.o 18lib-y += bb_qsort.o
21#lib-y += bb_strtod.o 19#lib-y += bb_strtod.o
22lib-y += bb_strtonum.o 20lib-y += bb_strtonum.o
23lib-y += change_identity.o
24lib-y += chomp.o 21lib-y += chomp.o
25lib-y += compare_string_array.o 22lib-y += compare_string_array.o
26lib-y += concat_path_file.o 23lib-y += concat_path_file.o
@@ -30,32 +27,23 @@ lib-y += copy_file.o
30lib-y += copyfd.o 27lib-y += copyfd.o
31lib-y += crc32.o 28lib-y += crc32.o
32lib-y += default_error_retval.o 29lib-y += default_error_retval.o
33lib-y += device_open.o
34lib-y += dump.o 30lib-y += dump.o
35lib-y += executable.o 31lib-y += executable.o
36lib-y += fclose_nonstdin.o 32lib-y += fclose_nonstdin.o
37lib-y += fflush_stdout_and_exit.o 33lib-y += fflush_stdout_and_exit.o
38lib-y += fgets_str.o 34lib-y += fgets_str.o
39lib-y += find_pid_by_name.o 35lib-y += find_pid_by_name.o
40lib-y += find_root_device.o
41lib-y += full_write.o 36lib-y += full_write.o
42lib-y += get_console.o
43lib-y += get_last_path_component.o 37lib-y += get_last_path_component.o
44lib-y += get_line_from_file.o 38lib-y += get_line_from_file.o
45lib-y += getpty.o 39lib-y += getopt32.o
46lib-y += get_volsize.o
47lib-y += herror_msg.o 40lib-y += herror_msg.o
48lib-y += human_readable.o 41lib-y += human_readable.o
49lib-y += inet_common.o
50lib-y += inode_hash.o
51lib-y += isdirectory.o 42lib-y += isdirectory.o
52lib-y += kernel_version.o
53lib-y += last_char_is.o 43lib-y += last_char_is.o
54lib-y += lineedit.o lineedit_ptr_hack.o 44lib-y += lineedit.o lineedit_ptr_hack.o
55lib-y += llist.o 45lib-y += llist.o
56lib-y += login.o
57lib-y += make_directory.o 46lib-y += make_directory.o
58lib-y += makedev.o
59lib-y += hash_md5_sha.o 47lib-y += hash_md5_sha.o
60lib-y += hash_sha1_x86-64.o 48lib-y += hash_sha1_x86-64.o
61lib-y += hash_sha1_hwaccel_x86-64.o 49lib-y += hash_sha1_hwaccel_x86-64.o
@@ -68,21 +56,18 @@ lib-y += messages.o
68lib-y += mode_string.o 56lib-y += mode_string.o
69lib-y += parse_mode.o 57lib-y += parse_mode.o
70lib-y += perror_msg.o 58lib-y += perror_msg.o
71lib-y += perror_nomsg.o
72lib-y += perror_nomsg_and_die.o 59lib-y += perror_nomsg_and_die.o
73lib-y += pidfile.o
74lib-y += platform.o 60lib-y += platform.o
75lib-y += popcnt.o 61lib-y += popcnt.o
76lib-y += printable.o 62lib-y += printable.o
77lib-y += printable_string.o 63lib-y += printable_string.o
78lib-y += print_flags.o
79lib-y += process_escape_sequence.o 64lib-y += process_escape_sequence.o
80lib-y += procps.o 65lib-y += procps.o
81lib-y += progress.o 66lib-y += progress.o
82lib-y += ptr_to_globals.o 67lib-y += ptr_to_globals.o
83lib-y += read.o 68lib-y += read.o
84lib-y += read_printf.o
85lib-y += read_key.o 69lib-y += read_key.o
70lib-y += read_printf.o
86lib-y += recursive_action.o 71lib-y += recursive_action.o
87lib-y += remove_file.o 72lib-y += remove_file.o
88lib-y += run_shell.o 73lib-y += run_shell.o
@@ -91,12 +76,9 @@ lib-y += safe_poll.o
91lib-y += safe_strncpy.o 76lib-y += safe_strncpy.o
92lib-y += safe_write.o 77lib-y += safe_write.o
93lib-y += securetty.o 78lib-y += securetty.o
94lib-y += setup_environment.o
95lib-y += signals.o
96lib-y += simplify_path.o 79lib-y += simplify_path.o
97lib-y += single_argv.o 80lib-y += single_argv.o
98lib-y += skip_whitespace.o 81lib-y += skip_whitespace.o
99lib-y += speed_table.o
100lib-y += str_tolower.o 82lib-y += str_tolower.o
101lib-y += strrstr.o 83lib-y += strrstr.o
102lib-y += sysconf.o 84lib-y += sysconf.o
@@ -109,17 +91,39 @@ lib-y += vfork_daemon_rexec.o
109lib-y += warn_ignoring_args.o 91lib-y += warn_ignoring_args.o
110lib-y += wfopen.o 92lib-y += wfopen.o
111lib-y += wfopen_input.o 93lib-y += wfopen_input.o
112lib-y += write.o
113lib-y += xatonum.o 94lib-y += xatonum.o
114lib-y += xconnect.o 95lib-y += xconnect.o
115lib-y += xfuncs.o 96lib-y += xfuncs.o
116lib-y += xfuncs_printf.o 97lib-y += xfuncs_printf.o
117lib-y += xfunc_die.o 98lib-y += xfunc_die.o
118lib-y += xgetcwd.o 99lib-y += xgetcwd.o
119lib-y += xgethostbyname.o
120lib-y += xreadlink.o 100lib-y += xreadlink.o
121lib-y += xrealloc_vector.o 101lib-y += xrealloc_vector.o
122 102
103lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o
104lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o
105lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o
106lib-$(CONFIG_PLATFORM_POSIX) += device_open.o
107lib-$(CONFIG_PLATFORM_POSIX) += find_root_device.o
108lib-$(CONFIG_PLATFORM_POSIX) += get_console.o
109lib-$(CONFIG_PLATFORM_POSIX) += getpty.o
110lib-$(CONFIG_PLATFORM_POSIX) += get_volsize.o
111lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o
112lib-$(CONFIG_PLATFORM_POSIX) += inode_hash.o
113lib-$(CONFIG_FEATURE_EXTRA_FILE_DATA) += inode_hash.o
114lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
115lib-$(CONFIG_PLATFORM_POSIX) += login.o
116lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
117lib-$(CONFIG_PLATFORM_POSIX) += perror_nomsg.o
118lib-$(CONFIG_PLATFORM_POSIX) += pidfile.o
119lib-$(CONFIG_PLATFORM_POSIX) += print_flags.o
120lib-$(CONFIG_PLATFORM_POSIX) += setup_environment.o
121lib-$(CONFIG_PLATFORM_POSIX) += signals.o
122lib-$(CONFIG_PLATFORM_POSIX) += speed_table.o
123lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
124lib-$(CONFIG_PLATFORM_POSIX) += write.o
125lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o
126
123lib-$(CONFIG_MOUNT) += match_fstype.o 127lib-$(CONFIG_MOUNT) += match_fstype.o
124lib-$(CONFIG_UMOUNT) += match_fstype.o 128lib-$(CONFIG_UMOUNT) += match_fstype.o
125 129
@@ -132,7 +136,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
132lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 136lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
133lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 137lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
134 138
135lib-$(CONFIG_NC) += udp_io.o 139lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
136lib-$(CONFIG_NETCAT) += udp_io.o 140lib-$(CONFIG_NETCAT) += udp_io.o
137lib-$(CONFIG_DNSD) += udp_io.o 141lib-$(CONFIG_DNSD) += udp_io.o
138lib-$(CONFIG_NTPD) += udp_io.o 142lib-$(CONFIG_NTPD) += udp_io.o
@@ -171,6 +175,7 @@ lib-$(CONFIG_MKE2FS) += find_mount_point.o
171lib-$(CONFIG_MKFS_REISER) += find_mount_point.o 175lib-$(CONFIG_MKFS_REISER) += find_mount_point.o
172lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o 176lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o
173lib-$(CONFIG_MOUNT) += find_mount_point.o 177lib-$(CONFIG_MOUNT) += find_mount_point.o
178lib-$(CONFIG_STAT) += find_mount_point.o
174 179
175lib-$(CONFIG_HWCLOCK) += rtc.o 180lib-$(CONFIG_HWCLOCK) += rtc.o
176lib-$(CONFIG_RTCWAKE) += rtc.o 181lib-$(CONFIG_RTCWAKE) += rtc.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d2e5900b5..b1064d10a 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -53,6 +53,15 @@ static inline int *get_perrno(void) { return &errno; }
53# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__ 53# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
54#endif 54#endif
55 55
56#if (ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32) || \
57 (ENABLE_PLATFORM_MINGW32 && (ENABLE_FEATURE_PREFER_APPLETS \
58 || ENABLE_FEATURE_SH_STANDALONE \
59 || ENABLE_FEATURE_SH_NOFORK))
60# define IF_FULL_LIST_OPTION(...) __VA_ARGS__
61#else
62# define IF_FULL_LIST_OPTION(...)
63#endif
64
56#include "usage_compressed.h" 65#include "usage_compressed.h"
57 66
58#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS 67#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
@@ -62,6 +71,7 @@ static inline int *get_perrno(void) { return &errno; }
62# define NUM_SCRIPTS 0 71# define NUM_SCRIPTS 0
63#endif 72#endif
64#if NUM_SCRIPTS > 0 73#if NUM_SCRIPTS > 0
74# define BB_ARCHIVE_PUBLIC
65# include "bb_archive.h" 75# include "bb_archive.h"
66static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; 76static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
67#endif 77#endif
@@ -90,6 +100,12 @@ static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
90# define ENABLE_FEATURE_COMPRESS_USAGE 0 100# define ENABLE_FEATURE_COMPRESS_USAGE 0
91#endif 101#endif
92 102
103#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1 && \
104 ENABLE_FEATURE_SH_STANDALONE
105static int find_applet_by_name_internal(const char *name);
106#else
107# define find_applet_by_name_internal(n) find_applet_by_name(n)
108#endif
93 109
94unsigned FAST_FUNC string_array_len(char **argv) 110unsigned FAST_FUNC string_array_len(char **argv)
95{ 111{
@@ -111,6 +127,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
111#if ENABLE_FEATURE_COMPRESS_USAGE 127#if ENABLE_FEATURE_COMPRESS_USAGE
112 128
113static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 129static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
130# define BB_ARCHIVE_PUBLIC
114# include "bb_archive.h" 131# include "bb_archive.h"
115# define unpack_usage_messages() \ 132# define unpack_usage_messages() \
116 unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE)) 133 unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE))
@@ -147,7 +164,7 @@ void FAST_FUNC bb_show_usage(void)
147#else 164#else
148 const char *p; 165 const char *p;
149 const char *usage_string = p = unpack_usage_messages(); 166 const char *usage_string = p = unpack_usage_messages();
150 int ap = find_applet_by_name(applet_name); 167 int ap = find_applet_by_name_internal(applet_name);
151 168
152 if (ap < 0 || usage_string == NULL) 169 if (ap < 0 || usage_string == NULL)
153 xfunc_die(); 170 xfunc_die();
@@ -156,7 +173,11 @@ void FAST_FUNC bb_show_usage(void)
156 ap--; 173 ap--;
157 } 174 }
158 full_write_fn(bb_banner); 175 full_write_fn(bb_banner);
176#if ENABLE_PLATFORM_MINGW32
177 full_write_fn("\n");
178#else
159 full_write_fn(" multi-call binary.\n"); /* common string */ 179 full_write_fn(" multi-call binary.\n"); /* common string */
180#endif
160 if (*p == '\b') 181 if (*p == '\b')
161 full_write_fn("\nNo help available\n"); 182 full_write_fn("\nNo help available\n");
162 else { 183 else {
@@ -176,7 +197,12 @@ void FAST_FUNC bb_show_usage(void)
176 xfunc_die(); 197 xfunc_die();
177} 198}
178 199
200#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1 && \
201 ENABLE_FEATURE_SH_STANDALONE
202static int find_applet_by_name_internal(const char *name)
203#else
179int FAST_FUNC find_applet_by_name(const char *name) 204int FAST_FUNC find_applet_by_name(const char *name)
205#endif
180{ 206{
181 unsigned i; 207 unsigned i;
182 int j; 208 int j;
@@ -241,6 +267,83 @@ int FAST_FUNC find_applet_by_name(const char *name)
241 return -1; 267 return -1;
242} 268}
243 269
270#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1
271# if ENABLE_FEATURE_SH_STANDALONE
272int FAST_FUNC find_applet_by_name_for_sh(const char *name, const char *path)
273{
274 int applet_no = find_applet_by_name_internal(name);
275 return applet_no >= 0 && prefer_applet(name, path) ? applet_no : -1;
276}
277
278int FAST_FUNC find_applet_by_name(const char *name)
279{
280 return find_applet_by_name_for_sh(name, NULL);
281}
282# endif
283
284# if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS
285static int external_exists(const char *name, const char *path)
286{
287 const char *path0, *path1, *ret;
288
289 path0 = path1 = xstrdup(path ?: getenv("PATH"));
290 ret = find_executable(name, &path1);
291 free((void *)ret);
292 free((void *)path0);
293 return ret != NULL;
294}
295
296static int prefer_applet_internal(const char *name, const char *path,
297 const char *override)
298{
299 const char *s, *sep;
300 size_t len;
301
302 if (override && *override) {
303 /* '-' disables all applets */
304 if (override[0] == '-' && override[1] == '\0')
305 return FALSE;
306
307 /* '+' each applet is overridden if an external command exists */
308 if (override[0] == '+' && override[1] == '\0')
309 return !external_exists(name, path);
310
311 /* Handle applets from a list separated by spaces, commas or
312 * semicolons. Applets before the first semicolon are disabled.
313 * Applets after the first semicolon are overridden if a
314 * corresponding external command exists. */
315 sep = strchr(override, ';');
316 len = strlen(name);
317 s = override - 1;
318 while (1) {
319 s = strstr(s + 1, name);
320 if (!s)
321 break;
322 /* neither "name.." nor "xxx,name.."? */
323 if (s != override && !strchr(" ,;", s[-1]))
324 continue;
325 /* neither "..name" nor "..name,xxx"? */
326 if (s[len] != '\0' && !strchr(" ,;", s[len]))
327 continue;
328 return (sep == NULL || s < sep) ?
329 FALSE : !external_exists(name, path);
330 }
331 }
332 return TRUE;
333}
334
335int FAST_FUNC prefer_applet(const char *name, const char *path)
336{
337 int ret;
338
339 ret = prefer_applet_internal(name, path, getenv(BB_OVERRIDE_APPLETS));
340 if (sizeof(CONFIG_OVERRIDE_APPLETS) > 1 && ret)
341 ret = prefer_applet_internal(name, path, CONFIG_OVERRIDE_APPLETS);
342 return ret;
343}
344# endif
345#endif
346
244 347
245void lbb_prepare(const char *applet 348void lbb_prepare(const char *applet
246 IF_FEATURE_INDIVIDUAL(, char **argv)) 349 IF_FEATURE_INDIVIDUAL(, char **argv))
@@ -291,6 +394,18 @@ const char *applet_name;
291#if !BB_MMU 394#if !BB_MMU
292bool re_execed; 395bool re_execed;
293#endif 396#endif
397#if ENABLE_PLATFORM_MINGW32
398static int interp = 0;
399char bb_comm[COMM_LEN];
400char bb_command_line[128];
401
402# if ENABLE_FEATURE_SH_STANDALONE
403void FAST_FUNC set_interp(int i)
404{
405 interp = i;
406}
407# endif
408#endif
294 409
295 410
296/* If not built as a single-applet executable... */ 411/* If not built as a single-applet executable... */
@@ -676,15 +791,36 @@ static void install_links(const char *busybox, int use_symbolic_links,
676 const char *appname = applet_names; 791 const char *appname = applet_names;
677 unsigned i; 792 unsigned i;
678 int rc; 793 int rc;
794# if ENABLE_PLATFORM_MINGW32
795 const char *sd = "";
796
797 if (custom_install_dir != NULL) {
798 bb_make_directory(custom_install_dir, 0755, FILEUTILS_RECUR);
799 }
800 else {
801 sd = get_system_drive();
802 for (i=1; i<ARRAY_SIZE(install_dir); ++i) {
803 fpc = concat_path_file(sd, install_dir[i]);
804 bb_make_directory(fpc, 0755, FILEUTILS_RECUR);
805 free(fpc);
806 }
807 }
808# endif
679 809
680 lf = link; 810 lf = link;
681 if (use_symbolic_links) 811 if (use_symbolic_links)
682 lf = symlink; 812 lf = symlink;
683 813
684 for (i = 0; i < ARRAY_SIZE(applet_main); i++) { 814 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
815# if ENABLE_PLATFORM_MINGW32
816 fpc = xasprintf("%s%s/%s.exe", sd,
817 custom_install_dir ?: install_dir[APPLET_INSTALL_LOC(i)],
818 appname);
819# else
685 fpc = concat_path_file( 820 fpc = concat_path_file(
686 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], 821 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
687 appname); 822 appname);
823# endif
688 // debug: bb_error_msg("%slinking %s to busybox", 824 // debug: bb_error_msg("%slinking %s to busybox",
689 // use_symbolic_links ? "sym" : "", fpc); 825 // use_symbolic_links ? "sym" : "", fpc);
690 rc = lf(busybox, fpc); 826 rc = lf(busybox, fpc);
@@ -781,20 +917,40 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
781 output_width = get_terminal_width(2); 917 output_width = get_terminal_width(2);
782 918
783 full_write1_str(bb_banner); /* reuse const string */ 919 full_write1_str(bb_banner); /* reuse const string */
920# if ENABLE_PLATFORM_MINGW32
921 full_write1_str("\n(");
922# if defined(MINGW_VER)
923 if (sizeof(MINGW_VER) > 5) {
924 full_write1_str(MINGW_VER "; ");
925 }
926# endif
927 full_write1_str(ENABLE_GLOBBING ? "glob" : "noglob");
928# if ENABLE_FEATURE_UTF8_MANIFEST
929 full_write1_str("; Unicode");
930# endif
931 full_write1_str(")\n\n");
932# else
784 full_write1_str(" multi-call binary.\n"); /* reuse */ 933 full_write1_str(" multi-call binary.\n"); /* reuse */
934#endif
785 full_write1_str( 935 full_write1_str(
786 "BusyBox is copyrighted by many authors between 1998-2015.\n" 936 "BusyBox is copyrighted by many authors between 1998-2025.\n"
787 "Licensed under GPLv2. See source distribution for detailed\n" 937 "Licensed under GPLv2. See source distribution for detailed\n"
788 "copyright notices.\n" 938 "copyright notices.\n"
789 "\n" 939 "\n"
790 "Usage: busybox [function [arguments]...]\n" 940 "Usage: busybox [function [arguments]...]\n"
791 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 941 " or: busybox --list"IF_FULL_LIST_OPTION("[-full]")"\n"
792# if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0 942# if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0
793 " or: busybox --show SCRIPT\n" 943 " or: busybox --show SCRIPT\n"
794# endif 944# endif
795 IF_FEATURE_INSTALLER( 945 IF_FEATURE_INSTALLER(
946 IF_NOT_PLATFORM_MINGW32(
796 " or: busybox --install [-s] [DIR]\n" 947 " or: busybox --install [-s] [DIR]\n"
797 ) 948 )
949 IF_PLATFORM_MINGW32(
950 " or: busybox --install [-s] [-u|DIR]\n"
951 " or: busybox --uninstall [-n] file\n"
952 )
953 )
798 " or: function [arguments]...\n" 954 " or: function [arguments]...\n"
799 "\n" 955 "\n"
800 IF_NOT_FEATURE_SH_STANDALONE( 956 IF_NOT_FEATURE_SH_STANDALONE(
@@ -854,9 +1010,28 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
854 unsigned i = 0; 1010 unsigned i = 0;
855 const char *a = applet_names; 1011 const char *a = applet_names;
856 while (*a) { 1012 while (*a) {
857# if ENABLE_FEATURE_INSTALLER 1013# if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
858 if (argv[1][6]) /* --list-full? */ 1014 if (argv[1][6]) /* --list-full? */
859 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 1015 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
1016# elif ENABLE_PLATFORM_MINGW32 && (ENABLE_FEATURE_PREFER_APPLETS \
1017 || ENABLE_FEATURE_SH_STANDALONE \
1018 || ENABLE_FEATURE_SH_NOFORK)
1019 if (argv[1][6]) { /* --list-full? */
1020 const char *str;
1021
1022 if (APPLET_IS_NOFORK(i))
1023 str = "NOFORK ";
1024 else if (APPLET_IS_NOEXEC(i))
1025 str = "noexec ";
1026# if NUM_SCRIPTS > 0
1027 else if (applet_main[i] == scripted_main)
1028 str = "script ";
1029# endif
1030 else
1031 str = " ";
1032 full_write1_str(str);
1033 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
1034 }
860# endif 1035# endif
861 full_write1_str(a); 1036 full_write1_str(a);
862 full_write1_str("\n"); 1037 full_write1_str("\n");
@@ -869,6 +1044,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
869 1044
870 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 1045 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
871 int use_symbolic_links; 1046 int use_symbolic_links;
1047#if !ENABLE_PLATFORM_MINGW32
872 const char *busybox; 1048 const char *busybox;
873 1049
874 busybox = xmalloc_readlink(bb_busybox_exec_path); 1050 busybox = xmalloc_readlink(bb_busybox_exec_path);
@@ -888,8 +1064,62 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
888 */ 1064 */
889 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 1065 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
890 install_links(busybox, use_symbolic_links, argv[2]); 1066 install_links(busybox, use_symbolic_links, argv[2]);
1067#else
1068 char *target;
1069 uint32_t opt;
1070 enum { OPT_s = (1 << 0), OPT_u = (1 << 1) };
1071
1072 /* busybox --install [-s] [-u|DIR]
1073 * -s: make symlinks
1074 * -u: install to Unix-style directories in system drive
1075 * DIR: directory to install links to
1076 * If no argument is provided put the links in the same directory
1077 * as busybox.
1078 */
1079 argv += 1;
1080 opt = getopt32(argv, "!su");
1081 argv += optind;
1082
1083 if (opt == (uint32_t)-1 ||
1084 (*argv != NULL && (opt & OPT_u || *(argv + 1) != NULL)))
1085 bb_simple_error_msg_and_die("busybox --install [-s] [-u|DIR]");
1086
1087 if (opt & OPT_u)
1088 target = NULL;
1089 else if (*argv != NULL)
1090 target = *argv;
1091 else
1092 target = dirname(xstrdup(bb_busybox_exec_path));
1093
1094 use_symbolic_links = opt & OPT_s;
1095 /* NULL target -> install to Unix-style dirs */
1096 install_links(bb_busybox_exec_path, use_symbolic_links, target);
1097#endif
1098 return 0;
1099 }
1100
1101#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_INSTALLER
1102 if (strcmp(argv[1], "--uninstall") == 0) {
1103 char name[PATH_MAX];
1104 int dry_run = (argv[2] && strcmp(argv[2], "-n") == 0 && ++argv);
1105 const char *file = argv[2];
1106
1107 if (!argv[2])
1108 bb_error_msg_and_die(bb_msg_requires_arg, "--uninstall");
1109
1110 while (enumerate_links(file, name)) {
1111 if (dry_run) {
1112 full_write1_str(name);
1113 full_write1_str("\n");
1114 }
1115 else if (unlink(name) != 0) {
1116 bb_simple_perror_msg(name);
1117 }
1118 file = NULL;
1119 }
891 return 0; 1120 return 0;
892 } 1121 }
1122#endif
893 1123
894 if (strcmp(argv[1], "--help") == 0) { 1124 if (strcmp(argv[1], "--help") == 0) {
895 /* "busybox --help [<applet>]" */ 1125 /* "busybox --help [<applet>]" */
@@ -902,7 +1132,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
902 /* convert to "<applet> --help" */ 1132 /* convert to "<applet> --help" */
903 applet_name = argv[0] = argv[2]; 1133 applet_name = argv[0] = argv[2];
904 argv[2] = NULL; 1134 argv[2] = NULL;
905 if (find_applet_by_name(applet_name) >= 0) { 1135 if (find_applet_by_name_internal(applet_name) >= 0) {
906 /* Make "--help foo" exit with 0: */ 1136 /* Make "--help foo" exit with 0: */
907 xfunc_error_retval = 0; 1137 xfunc_error_retval = 0;
908 bb_show_usage(); 1138 bb_show_usage();
@@ -913,6 +1143,10 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
913 /* We support "busybox /a/path/to/applet args..." too. Allows for 1143 /* We support "busybox /a/path/to/applet args..." too. Allows for
914 * "#!/bin/busybox"-style wrappers 1144 * "#!/bin/busybox"-style wrappers
915 */ 1145 */
1146# if ENABLE_PLATFORM_MINGW32
1147 if (interp)
1148 --interp;
1149# endif
916 applet_name = bb_get_last_path_component_nostrip(argv[0]); 1150 applet_name = bb_get_last_path_component_nostrip(argv[0]);
917 } 1151 }
918 run_applet_and_exit(applet_name, argv); 1152 run_applet_and_exit(applet_name, argv);
@@ -943,6 +1177,9 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no UNUSED_PARAM, char **a
943# if ENABLE_TEST1 || ENABLE_TEST2 1177# if ENABLE_TEST1 || ENABLE_TEST2
944 && argv[0][0] != '[' /* exclude [ --help ] and [[ --help ]] too */ 1178 && argv[0][0] != '[' /* exclude [ --help ] and [[ --help ]] too */
945# endif 1179# endif
1180# if ENABLE_PLATFORM_MINGW32 && defined APPLET_NO_busybox
1181 && applet_no != APPLET_NO_busybox
1182# endif
946 ) { 1183 ) {
947 if (argv[1] && strcmp(argv[1], "--help") == 0) { 1184 if (argv[1] && strcmp(argv[1], "--help") == 0) {
948 /* Make "foo --help [...]" exit with 0: */ 1185 /* Make "foo --help [...]" exit with 0: */
@@ -954,7 +1191,14 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no UNUSED_PARAM, char **a
954 1191
955void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) 1192void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv)
956{ 1193{
1194# if ENABLE_PLATFORM_MINGW32
1195 int argc = string_array_len(argv);
1196 int i;
1197 const char *vmask;
1198 unsigned int mask;
1199# else
957 int argc; 1200 int argc;
1201# endif
958 1202
959 /* 1203 /*
960 * We do not use argv[0]: do not want to repeat massaging of 1204 * We do not use argv[0]: do not want to repeat massaging of
@@ -967,7 +1211,23 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar
967 if (ENABLE_FEATURE_SUID) 1211 if (ENABLE_FEATURE_SUID)
968 check_suid(applet_no); 1212 check_suid(applet_no);
969 1213
1214# if ENABLE_PLATFORM_MINGW32
1215 safe_strncpy(bb_comm,
1216 interp ? bb_basename(argv[interp]) : applet_name,
1217 sizeof(bb_comm));
1218
1219 safe_strncpy(bb_command_line, applet_name, sizeof(bb_command_line));
1220 for (i=1; i < argc && argv[i] &&
1221 strlen(bb_command_line) + strlen(argv[i]) + 2 < 128; ++i) {
1222 strcat(strcat(bb_command_line, " "), argv[i]);
1223 }
1224
1225 vmask = getenv("BB_UMASK");
1226 if (vmask && sscanf(vmask, "%o", &mask) == 1)
1227 umask((mode_t)mask);
1228# else
970 argc = string_array_len(argv); 1229 argc = string_array_len(argv);
1230# endif
971 xfunc_error_retval = applet_main[applet_no](argc, argv); 1231 xfunc_error_retval = applet_main[applet_no](argc, argv);
972 1232
973 /* Note: applet_main() may also not return (die on a xfunc or such) */ 1233 /* Note: applet_main() may also not return (die on a xfunc or such) */
@@ -985,7 +1245,7 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv)
985# if NUM_APPLETS > 0 1245# if NUM_APPLETS > 0
986 /* find_applet_by_name() search is more expensive, so goes second */ 1246 /* find_applet_by_name() search is more expensive, so goes second */
987 { 1247 {
988 int applet = find_applet_by_name(name); 1248 int applet = find_applet_by_name_internal(name);
989 if (applet >= 0) 1249 if (applet >= 0)
990 run_applet_no_and_exit(applet, name, argv); 1250 run_applet_no_and_exit(applet, name, argv);
991 } 1251 }
@@ -1077,6 +1337,44 @@ int main(int argc UNUSED_PARAM, char **argv)
1077 argv[0][0] &= 0x7f; 1337 argv[0][0] &= 0x7f;
1078 } 1338 }
1079#endif 1339#endif
1340#if ENABLE_PLATFORM_MINGW32
1341# if ENABLE_FEATURE_UTF8_MANIFEST
1342 if (GetACP() != CP_UTF8) {
1343 full_write2_str(bb_basename(argv[0]));
1344 full_write2_str(": UTF8 manifest not supported\n");
1345 return 1;
1346 }
1347# endif
1348
1349 /* detect if we're running an interpreted script */
1350 if (argv[0][1] == ':' && argv[0][2] == '/') {
1351 switch (argv[0][0]) {
1352 case '2':
1353 ++interp;
1354 /* fall through */
1355 case '1':
1356 ++interp;
1357 argv[0] += 3;
1358 break;
1359 }
1360 }
1361
1362 /* Have this process handle critical errors itself: the default
1363 * system-generated error dialogs may be inconvenient. */
1364 change_critical_error_dialogs(getenv(BB_CRITICAL_ERROR_DIALOGS));
1365#endif
1366
1367#if defined(__MINGW64_VERSION_MAJOR)
1368 if ( stdin ) {
1369 _setmode(fileno(stdin), _O_BINARY);
1370 }
1371 if ( stdout ) {
1372 _setmode(fileno(stdout), _O_BINARY);
1373 }
1374 if ( stderr ) {
1375 _setmode(fileno(stderr), _O_BINARY);
1376 }
1377#endif
1080 1378
1081#if defined(SINGLE_APPLET_MAIN) 1379#if defined(SINGLE_APPLET_MAIN)
1082 1380
@@ -1101,6 +1399,10 @@ int main(int argc UNUSED_PARAM, char **argv)
1101 1399
1102#else 1400#else
1103 1401
1402# if ENABLE_PLATFORM_MINGW32
1403 if (argv[1] && argv[2] && strcmp(argv[1], "--busybox") == 0)
1404 argv += 2;
1405# endif
1104 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); 1406 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
1105# if !ENABLE_BUSYBOX 1407# if !ENABLE_BUSYBOX
1106 if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) 1408 if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox"))
@@ -1109,6 +1411,27 @@ int main(int argc UNUSED_PARAM, char **argv)
1109 applet_name = argv[0]; 1411 applet_name = argv[0];
1110 if (applet_name[0] == '-') 1412 if (applet_name[0] == '-')
1111 applet_name++; 1413 applet_name++;
1414# if ENABLE_PLATFORM_MINGW32
1415 str_tolower(argv[0]);
1416 bs_to_slash(argv[0]);
1417 if (has_exe_suffix_or_dot(argv[0])) {
1418 char *s = strrchr(argv[0], '.');
1419 if (s)
1420 *s = '\0';
1421 }
1422
1423 if (windows_env()) {
1424 /* remove single trailing separator from PATH */
1425 for (char **envp = environ; envp && *envp; envp++) {
1426 if (is_prefixed_with_case(*envp, "PATH=")) {
1427 char *end = last_char_is(*envp, ';');
1428 if (end && end[-1] != ';')
1429 *end = '\0';
1430 break;
1431 }
1432 }
1433 }
1434# endif
1112 applet_name = bb_basename(applet_name); 1435 applet_name = bb_basename(applet_name);
1113 1436
1114 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */ 1437 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */
diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c
index 31cff2b41..757b80be8 100644
--- a/libbb/bb_getgroups.c
+++ b/libbb/bb_getgroups.c
@@ -10,6 +10,7 @@
10 10
11#include "libbb.h" 11#include "libbb.h"
12 12
13#if !ENABLE_PLATFORM_MINGW32
13gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) 14gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
14{ 15{
15 int n = ngroups ? *ngroups : 0; 16 int n = ngroups ? *ngroups : 0;
@@ -45,6 +46,7 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
45 *ngroups = n; 46 *ngroups = n;
46 return group_array; 47 return group_array;
47} 48}
49#endif
48 50
49uid_t FAST_FUNC get_cached_euid(uid_t *euid) 51uid_t FAST_FUNC get_cached_euid(uid_t *euid)
50{ 52{
@@ -60,6 +62,11 @@ gid_t FAST_FUNC get_cached_egid(gid_t *egid)
60 return *egid; 62 return *egid;
61} 63}
62 64
65#if !ENABLE_PLATFORM_MINGW32
66// Both current callers of is_in_supplementary_groups() check the gid
67// first. Our implementation of getgroups() provides no additional
68// information so there's no reason to call it.
69
63/* Return non-zero if GID is in our supplementary group list. */ 70/* Return non-zero if GID is in our supplementary group list. */
64int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) 71int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid)
65{ 72{
@@ -79,3 +86,4 @@ int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid
79 86
80 return 0; 87 return 0;
81} 88}
89#endif
diff --git a/libbb/bitops.c b/libbb/bitops.c
new file mode 100644
index 000000000..467e1a2d9
--- /dev/null
+++ b/libbb/bitops.c
@@ -0,0 +1,128 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//kbuild:lib-y += bitops.o
9
10#include "libbb.h"
11
12void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count)
13{
14 uint8_t *d = dst;
15 const uint8_t *s1 = src1;
16 const uint8_t *s2 = src2;
17#if BB_UNALIGNED_MEMACCESS_OK
18 while (count >= sizeof(long)) {
19 *(long*)d = *(long*)s1 ^ *(long*)s2;
20 count -= sizeof(long);
21 d += sizeof(long);
22 s1 += sizeof(long);
23 s2 += sizeof(long);
24 }
25#endif
26 while (count--)
27 *d++ = *s1++ ^ *s2++;
28}
29
30void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count)
31{
32 xorbuf_3(dst, dst, src, count);
33}
34
35void FAST_FUNC xorbuf16_aligned_long(void *dst, const void *src)
36{
37#if defined(__SSE__) /* any x86_64 has it */
38 asm volatile(
39"\n movups (%0),%%xmm0"
40"\n movups (%1),%%xmm1" // can't just xorps(%1),%%xmm0:
41"\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment
42"\n movups %%xmm0,(%0)"
43"\n"
44 : "=r" (dst), "=r" (src)
45 : "0" (dst), "1" (src)
46 : "xmm0", "xmm1", "memory"
47 );
48#else
49 unsigned long *d = dst;
50 const unsigned long *s = src;
51 d[0] ^= s[0];
52# if LONG_MAX <= 0x7fffffffffffffff
53 d[1] ^= s[1];
54# if LONG_MAX == 0x7fffffff
55 d[2] ^= s[2];
56 d[3] ^= s[3];
57# endif
58# endif
59#endif
60}
61// The above can be inlined in libbb.h, in a way where compiler
62// is even free to use better addressing modes than (%reg), and
63// to keep the result in a register
64// (to not store it to memory after each XOR):
65//#if defined(__SSE__)
66//#include <xmmintrin.h>
67//^^^ or just: typedef float __m128_u attribute((__vector_size__(16),__may_alias__,__aligned__(1)));
68//static ALWAYS_INLINE void xorbuf16_aligned_long(void *dst, const void *src)
69//{
70// __m128_u xmm0, xmm1;
71// asm volatile(
72//"\n xorps %1,%0"
73// : "=x" (xmm0), "=x" (xmm1)
74// : "0" (*(__m128_u*)dst), "1" (*(__m128_u*)src)
75// );
76// *(__m128_u*)dst = xmm0; // this store may be optimized out!
77//}
78//#endif
79// but I don't trust gcc optimizer enough to not generate some monstrosity.
80// See GMULT() function in TLS code as an example.
81
82void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2)
83{
84#if defined(__SSE__) /* any x86_64 has it */
85 asm volatile(
86"\n movups 0*16(%1),%%xmm0"
87"\n movups 0*16(%2),%%xmm1" // can't just xorps(%2),%%xmm0:
88"\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment, we have only 8-byte
89"\n movups %%xmm0,0*16(%0)"
90"\n movups 1*16(%1),%%xmm0"
91"\n movups 1*16(%2),%%xmm1"
92"\n xorps %%xmm1,%%xmm0"
93"\n movups %%xmm0,1*16(%0)"
94"\n movups 2*16(%1),%%xmm0"
95"\n movups 2*16(%2),%%xmm1"
96"\n xorps %%xmm1,%%xmm0"
97"\n movups %%xmm0,2*16(%0)"
98"\n movups 3*16(%1),%%xmm0"
99"\n movups 3*16(%2),%%xmm1"
100"\n xorps %%xmm1,%%xmm0"
101"\n movups %%xmm0,3*16(%0)"
102"\n"
103 : "=r" (dst), "=r" (src1), "=r" (src2)
104 : "0" (dst), "1" (src1), "2" (src2)
105 : "xmm0", "xmm1", "memory"
106 );
107#else
108 long *d = dst;
109 const long *s1 = src1;
110 const long *s2 = src2;
111 unsigned count = 64 / sizeof(long);
112 do {
113 *d++ = *s1++ ^ *s2++;
114 } while (--count != 0);
115#endif
116}
117
118#if !BB_UNALIGNED_MEMACCESS_OK
119void FAST_FUNC xorbuf16(void *dst, const void *src)
120{
121#define p_aligned(a) (((uintptr_t)(a) & (sizeof(long)-1)) == 0)
122 if (p_aligned(src) && p_aligned(dst)) {
123 xorbuf16_aligned_long(dst, src);
124 return;
125 }
126 xorbuf_3(dst, dst, src, 16);
127}
128#endif
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
index d8cd033a3..70a4c29cf 100644
--- a/libbb/compare_string_array.c
+++ b/libbb/compare_string_array.c
@@ -27,11 +27,25 @@ char* FAST_FUNC is_prefixed_with(const char *string, const char *key)
27#endif 27#endif
28} 28}
29 29
30#if ENABLE_PLATFORM_MINGW32
31char* FAST_FUNC is_prefixed_with_case(const char *string, const char *key)
32{
33 while (*key != '\0') {
34 if (tolower(*key) != tolower(*string))
35 return NULL;
36 key++;
37 string++;
38 }
39 return (char*)string;
40}
41#endif
42
30/* 43/*
31 * Return NULL if string is not suffixed with key. Return pointer to the 44 * Return NULL if string is not suffixed with key. Return pointer to the
32 * beginning of prefix key in string. If key is an empty string return pointer 45 * beginning of prefix key in string. If key is an empty string return pointer
33 * to the end of string. 46 * to the end of string.
34 */ 47 */
48#if !ENABLE_PLATFORM_MINGW32
35char* FAST_FUNC is_suffixed_with(const char *string, const char *key) 49char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
36{ 50{
37 size_t key_len = strlen(key); 51 size_t key_len = strlen(key);
@@ -46,6 +60,33 @@ char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
46 60
47 return NULL; 61 return NULL;
48} 62}
63#else
64static char* FAST_FUNC is_suffixed(const char *string, const char *key,
65 int (*fn)(const char *, const char*))
66{
67 size_t key_len = strlen(key);
68 ssize_t len_diff = strlen(string) - key_len;
69
70 if (len_diff >= 0) {
71 string += len_diff;
72 if (fn(string, key) == 0) {
73 return (char*)string;
74 }
75 }
76
77 return NULL;
78}
79
80char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
81{
82 return is_suffixed(string, key, strcmp);
83}
84
85char* FAST_FUNC is_suffixed_with_case(const char *string, const char *key)
86{
87 return is_suffixed(string, key, strcasecmp);
88}
89#endif
49 90
50/* returns the array index of the string */ 91/* returns the array index of the string */
51/* (index of first match is returned, or -1) */ 92/* (index of first match is returned, or -1) */
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index 5b4b7f113..3afb0e3a4 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -21,8 +21,14 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename)
21 21
22 if (!path) 22 if (!path)
23 path = ""; 23 path = "";
24#if ENABLE_PLATFORM_MINGW32
25 lc = last_char_is_dir_sep(path);
26 while (is_dir_sep(*filename))
27 filename++;
28#else
24 lc = last_char_is(path, '/'); 29 lc = last_char_is(path, '/');
25 while (*filename == '/') 30 while (*filename == '/')
26 filename++; 31 filename++;
32#endif
27 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); 33 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
28} 34}
diff --git a/libbb/const_hack.c b/libbb/const_hack.c
index 9575e6d67..1d175481b 100644
--- a/libbb/const_hack.c
+++ b/libbb/const_hack.c
@@ -9,8 +9,27 @@
9#include "libbb.h" 9#include "libbb.h"
10 10
11#if defined(__clang_major__) && __clang_major__ >= 9 11#if defined(__clang_major__) && __clang_major__ >= 9
12/* Clang/llvm drops assignment to "constant" storage. Silently.
13 * Needs serious convincing to not eliminate the store.
14 */
15static ALWAYS_INLINE void* not_const_pp(const void *p)
16{
17 void *pp;
18 asm volatile (
19 "# forget that p points to const"
20 : /*outputs*/ "=r" (pp)
21 : /*inputs*/ "0" (p)
22 );
23 return pp;
24}
25void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, void *v)
26{
27 *(void**)not_const_pp(pptr) = v;
28 barrier();
29}
12void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) 30void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size)
13{ 31{
14 ASSIGN_CONST_PTR(pptr, xzalloc(size)); 32 *(void**)not_const_pp(pptr) = xzalloc(size);
33 barrier();
15} 34}
16#endif 35#endif
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 044bc3c20..c0928a5a8 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -105,12 +105,18 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
105 return -1; 105 return -1;
106 } 106 }
107 } else { 107 } else {
108#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
108 if (source_stat.st_dev == dest_stat.st_dev 109 if (source_stat.st_dev == dest_stat.st_dev
109 && source_stat.st_ino == dest_stat.st_ino 110 && source_stat.st_ino == dest_stat.st_ino
111# if ENABLE_FEATURE_EXTRA_FILE_DATA
112 /* ignore invalid inode numbers */
113 && source_stat.st_ino != 0
114# endif
110 ) { 115 ) {
111 bb_error_msg("'%s' and '%s' are the same file", source, dest); 116 bb_error_msg("'%s' and '%s' are the same file", source, dest);
112 return -1; 117 return -1;
113 } 118 }
119#endif
114 if (flags & FILEUTILS_NO_OVERWRITE) /* cp -n */ 120 if (flags & FILEUTILS_NO_OVERWRITE) /* cp -n */
115 return 0; 121 return 0;
116 dest_exists = 1; 122 dest_exists = 1;
diff --git a/libbb/dump.c b/libbb/dump.c
index 2ca9919da..b2abe85af 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -36,6 +36,9 @@ typedef struct priv_dumper_t {
36 off_t eaddress; /* end address */ 36 off_t eaddress; /* end address */
37 int blocksize; 37 int blocksize;
38 smallint exitval; /* final exit value */ 38 smallint exitval; /* final exit value */
39#if ENABLE_PLATFORM_MINGW32
40 FILE *fd;
41#endif
39 42
40 /* former statics */ 43 /* former statics */
41 smallint next__done; 44 smallint next__done;
@@ -59,6 +62,9 @@ dumper_t* FAST_FUNC alloc_dumper(void)
59 dumper->pub.dump_length = -1; 62 dumper->pub.dump_length = -1;
60 dumper->pub.dump_vflag = FIRST; 63 dumper->pub.dump_vflag = FIRST;
61 dumper->get__ateof = 1; 64 dumper->get__ateof = 1;
65#if ENABLE_PLATFORM_MINGW32
66 dumper->fd = stdin;
67#endif
62 return &dumper->pub; 68 return &dumper->pub;
63} 69}
64 70
@@ -335,7 +341,11 @@ static void do_skip(priv_dumper_t *dumper, const char *fname)
335{ 341{
336 struct stat sbuf; 342 struct stat sbuf;
337 343
344#if ENABLE_PLATFORM_MINGW32
345 xfstat(fileno(dumper->fd), &sbuf, fname);
346#else
338 xfstat(STDIN_FILENO, &sbuf, fname); 347 xfstat(STDIN_FILENO, &sbuf, fname);
348#endif
339 if (S_ISREG(sbuf.st_mode) 349 if (S_ISREG(sbuf.st_mode)
340 && dumper->pub.dump_skip >= sbuf.st_size 350 && dumper->pub.dump_skip >= sbuf.st_size
341 ) { 351 ) {
@@ -344,7 +354,11 @@ static void do_skip(priv_dumper_t *dumper, const char *fname)
344 dumper->pub.address += sbuf.st_size; 354 dumper->pub.address += sbuf.st_size;
345 return; 355 return;
346 } 356 }
357#if ENABLE_PLATFORM_MINGW32
358 if (fseeko(dumper->fd, dumper->pub.dump_skip, SEEK_SET)) {
359#else
347 if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) { 360 if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) {
361#endif
348 bb_simple_perror_msg_and_die(fname); 362 bb_simple_perror_msg_and_die(fname);
349 } 363 }
350 dumper->pub.address += dumper->pub.dump_skip; 364 dumper->pub.address += dumper->pub.dump_skip;
@@ -360,13 +374,23 @@ static NOINLINE int next(priv_dumper_t *dumper)
360 if (fname) { 374 if (fname) {
361 dumper->argv++; 375 dumper->argv++;
362 if (NOT_LONE_DASH(fname)) { 376 if (NOT_LONE_DASH(fname)) {
377#if ENABLE_PLATFORM_MINGW32
378 dumper->fd = fopen(fname, "r");
379 if (!dumper->fd) {
380#else
363 if (!freopen(fname, "r", stdin)) { 381 if (!freopen(fname, "r", stdin)) {
382#endif
364 bb_simple_perror_msg(fname); 383 bb_simple_perror_msg(fname);
365 dumper->exitval = 1; 384 dumper->exitval = 1;
366 dumper->next__done = 1; 385 dumper->next__done = 1;
367 continue; 386 continue;
368 } 387 }
369 } 388 }
389#if ENABLE_PLATFORM_MINGW32
390 else {
391 dumper->fd = stdin;
392 }
393#endif
370 } else { 394 } else {
371 if (dumper->next__done) 395 if (dumper->next__done)
372 return 0; /* no next file */ 396 return 0; /* no next file */
@@ -421,13 +445,25 @@ static unsigned char *get(priv_dumper_t *dumper)
421 dumper->eaddress = dumper->pub.address + nread; 445 dumper->eaddress = dumper->pub.address + nread;
422 return dumper->get__curp; 446 return dumper->get__curp;
423 } 447 }
448#if ENABLE_PLATFORM_MINGW32
449 n = fread(dumper->get__curp + nread, sizeof(unsigned char),
450 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), dumper->fd);
451#else
424 n = fread(dumper->get__curp + nread, sizeof(unsigned char), 452 n = fread(dumper->get__curp + nread, sizeof(unsigned char),
425 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin); 453 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
454#endif
426 if (n == 0) { 455 if (n == 0) {
456#if ENABLE_PLATFORM_MINGW32
457 if (ferror(dumper->fd)) {
458#else
427 if (ferror(stdin)) { 459 if (ferror(stdin)) {
460#endif
428 bb_simple_perror_msg(dumper->argv[-1]); 461 bb_simple_perror_msg(dumper->argv[-1]);
429 } 462 }
430 dumper->get__ateof = 1; 463 dumper->get__ateof = 1;
464#if ENABLE_PLATFORM_MINGW32
465 fclose(dumper->fd);
466#endif
431 continue; 467 continue;
432 } 468 }
433 dumper->get__ateof = 0; 469 dumper->get__ateof = 0;
@@ -667,15 +703,21 @@ static NOINLINE void display(priv_dumper_t* dumper)
667 conv_u(pr, bp); 703 conv_u(pr, bp);
668 break; 704 break;
669 case F_UINT: { 705 case F_UINT: {
706 union {
707 uint16_t uval16;
708 uint32_t uval32;
709 } u;
670 unsigned value = (unsigned char)*bp; 710 unsigned value = (unsigned char)*bp;
671 switch (pr->bcnt) { 711 switch (pr->bcnt) {
672 case 1: 712 case 1:
673 break; 713 break;
674 case 2: 714 case 2:
675 move_from_unaligned16(value, bp); 715 move_from_unaligned16(u.uval16, bp);
716 value = u.uval16;
676 break; 717 break;
677 case 4: 718 case 4:
678 move_from_unaligned32(value, bp); 719 move_from_unaligned32(u.uval32, bp);
720 value = u.uval32;
679 break; 721 break;
680 /* case 8: no users yet */ 722 /* case 8: no users yet */
681 } 723 }
diff --git a/libbb/executable.c b/libbb/executable.c
index 09bed1eaf..263141912 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -15,7 +15,12 @@
15int FAST_FUNC file_is_executable(const char *name) 15int FAST_FUNC file_is_executable(const char *name)
16{ 16{
17 struct stat s; 17 struct stat s;
18#if !ENABLE_PLATFORM_MINGW32
18 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode)); 19 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
20#else
21 /* expand WIN32 implementation of access(2) */
22 return (!stat(name, &s) && S_ISREG(s.st_mode) && (s.st_mode & S_IXUSR));
23#endif
19} 24}
20 25
21/* search (*PATHp) for an executable file; 26/* search (*PATHp) for an executable file;
@@ -40,8 +45,9 @@ char* FAST_FUNC find_executable(const char *name, const char **PATHp)
40 if (!p) 45 if (!p)
41 return NULL; 46 return NULL;
42 while (1) { 47 while (1) {
43 const char *end = strchrnul(p, ':'); 48 const char *end = strchrnul(p, PATH_SEP);
44 int sz = end - p; 49 int sz = end - p;
50 int ex;
45 51
46 if (sz != 0) { 52 if (sz != 0) {
47 p = xasprintf("%.*s/%s", sz, p, name); 53 p = xasprintf("%.*s/%s", sz, p, name);
@@ -55,7 +61,19 @@ char* FAST_FUNC find_executable(const char *name, const char **PATHp)
55// With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy, 61// With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy,
56// current dir is not tried the second time. 62// current dir is not tried the second time.
57 } 63 }
58 if (file_is_executable(p)) { 64#if ENABLE_PLATFORM_MINGW32
65 {
66 char *w = file_is_win32_exe(p);
67 ex = w != NULL;
68 if (ex) {
69 free(p);
70 p = w;
71 }
72 }
73#else
74 ex = file_is_executable(p);
75#endif
76 if (ex) {
59 *PATHp = (*end ? end+1 : NULL); 77 *PATHp = (*end ? end+1 : NULL);
60 return p; 78 return p;
61 } 79 }
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 0e1be3820..cf06c6e18 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -6,6 +6,9 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9#if ENABLE_PLATFORM_MINGW32
10# define MNTENT_PRIVATE
11#endif
9#include "libbb.h" 12#include "libbb.h"
10#include <mntent.h> 13#include <mntent.h>
11 14
@@ -19,14 +22,22 @@
19struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) 22struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
20{ 23{
21 struct stat s; 24 struct stat s;
25#if !ENABLE_PLATFORM_MINGW32
22 FILE *mtab_fp; 26 FILE *mtab_fp;
23 struct mntent *mountEntry; 27 struct mntent *mountEntry;
24 dev_t devno_of_name; 28 dev_t devno_of_name;
25 bool block_dev; 29 bool block_dev;
30#else
31 struct mntent *mountEntry;
32 static struct mntdata *data = NULL;
33 char *current;
34 const char *path;
35#endif
26 36
27 if (stat(name, &s) != 0) 37 if (stat(name, &s) != 0)
28 return NULL; 38 return NULL;
29 39
40#if !ENABLE_PLATFORM_MINGW32
30 devno_of_name = s.st_dev; 41 devno_of_name = s.st_dev;
31 block_dev = 0; 42 block_dev = 0;
32 /* Why S_ISCHR? - UBI volumes use char devices, not block */ 43 /* Why S_ISCHR? - UBI volumes use char devices, not block */
@@ -74,6 +85,26 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
74 } 85 }
75 } 86 }
76 endmntent(mtab_fp); 87 endmntent(mtab_fp);
88#else
89 mountEntry = NULL;
90 path = NULL;
91 current = NULL;
92
93 if ( isalpha(name[0]) && name[1] == ':' ) {
94 path = name;
95 } else {
96 path = current = xrealloc_getcwd_or_warn(NULL);
97 }
98
99 if ( path && isalpha(path[0]) && path[1] == ':' ) {
100 if (data == NULL)
101 data = xmalloc(sizeof(*data));
102
103 fill_mntdata(data, toupper(path[0]) - 'A');
104 mountEntry = &data->me;
105 }
106 free(current);
107#endif
77 108
78 return mountEntry; 109 return mountEntry;
79} 110}
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
index fe13f7211..0b6d5a206 100644
--- a/libbb/find_pid_by_name.c
+++ b/libbb/find_pid_by_name.c
@@ -39,8 +39,10 @@ and therefore comm field contains "exe".
39 39
40static int comm_match(procps_status_t *p, const char *procName) 40static int comm_match(procps_status_t *p, const char *procName)
41{ 41{
42#if !ENABLE_PLATFORM_MINGW32
42 int argv1idx; 43 int argv1idx;
43 const char *argv1; 44 const char *argv1;
45#endif
44 46
45 if (strncmp(p->comm, procName, 15) != 0) 47 if (strncmp(p->comm, procName, 15) != 0)
46 return 0; /* comm does not match */ 48 return 0; /* comm does not match */
@@ -55,6 +57,7 @@ static int comm_match(procps_status_t *p, const char *procName)
55 * This can be crazily_long_script_name.sh! 57 * This can be crazily_long_script_name.sh!
56 * The telltale sign is basename(argv[1]) == procName */ 58 * The telltale sign is basename(argv[1]) == procName */
57 59
60#if !ENABLE_PLATFORM_MINGW32
58 if (!p->argv0) 61 if (!p->argv0)
59 return 0; 62 return 0;
60 63
@@ -65,6 +68,7 @@ static int comm_match(procps_status_t *p, const char *procName)
65 68
66 if (strcmp(bb_basename(argv1), procName) != 0) 69 if (strcmp(bb_basename(argv1), procName) != 0)
67 return 0; 70 return 0;
71#endif
68 72
69 return 1; 73 return 1;
70} 74}
@@ -87,6 +91,7 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName)
87 pidList = xzalloc(sizeof(*pidList)); 91 pidList = xzalloc(sizeof(*pidList));
88 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) { 92 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) {
89 if (comm_match(p, procName) 93 if (comm_match(p, procName)
94#if !ENABLE_PLATFORM_MINGW32
90 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ 95 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
91 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) 96 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
92 /* or we require /proc/PID/exe link to match */ 97 /* or we require /proc/PID/exe link to match */
@@ -95,6 +100,7 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName)
95 : bb_basename(p->exe), 100 : bb_basename(p->exe),
96 procName 101 procName
97 ) == 0) 102 ) == 0)
103#endif
98 ) { 104 ) {
99 pidList = xrealloc_vector(pidList, 2, i); 105 pidList = xrealloc_vector(pidList, 2, i);
100 pidList[i++] = p->pid; 106 pidList[i++] = p->pid;
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
index 04fdf2a3e..46a87d7fc 100644
--- a/libbb/get_last_path_component.c
+++ b/libbb/get_last_path_component.c
@@ -10,12 +10,34 @@
10 10
11const char* FAST_FUNC bb_basename(const char *name) 11const char* FAST_FUNC bb_basename(const char *name)
12{ 12{
13#if ENABLE_PLATFORM_MINGW32
14 const char *cp;
15 for (cp = name; *cp; cp++)
16 if (*cp == '/' || *cp == '\\' || *cp == ':')
17 name = cp + 1;
18#else
13 const char *cp = strrchr(name, '/'); 19 const char *cp = strrchr(name, '/');
14 if (cp) 20 if (cp)
15 return cp + 1; 21 return cp + 1;
22#endif
16 return name; 23 return name;
17} 24}
18 25
26#if ENABLE_PLATFORM_MINGW32
27char * FAST_FUNC get_last_slash(const char *path)
28{
29 const char *start = path + root_len(path);
30 char *slash = strrchr(start, '/');
31 char *bslash = strrchr(start, '\\');
32
33 if (slash && bslash)
34 slash = MAX(slash, bslash);
35 else if (!slash)
36 slash = bslash;
37 return slash;
38}
39#endif
40
19/* 41/*
20 * "/" -> "/" 42 * "/" -> "/"
21 * "abc" -> "abc" 43 * "abc" -> "abc"
@@ -24,10 +46,20 @@ const char* FAST_FUNC bb_basename(const char *name)
24 */ 46 */
25char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path) 47char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
26{ 48{
49#if ENABLE_PLATFORM_MINGW32
50 const char *start = path + root_len(path);
51 char *slash = get_last_slash(path);
52
53 if (!slash && has_dos_drive_prefix(path) && path[2] != '\0')
54 return (char *)path + 2;
55 if (!slash || (slash == start && !slash[1]))
56 return (char*)path;
57#else
27 char *slash = strrchr(path, '/'); 58 char *slash = strrchr(path, '/');
28 59
29 if (!slash || (slash == path && !slash[1])) 60 if (!slash || (slash == path && !slash[1]))
30 return (char*)path; 61 return (char*)path;
62#endif
31 63
32 return slash + 1; 64 return slash + 1;
33} 65}
@@ -40,11 +72,20 @@ char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
40 */ 72 */
41char* FAST_FUNC bb_get_last_path_component_strip(char *path) 73char* FAST_FUNC bb_get_last_path_component_strip(char *path)
42{ 74{
75#if ENABLE_PLATFORM_MINGW32
76 char *slash = last_char_is_dir_sep(path);
77 const char *start = has_dos_drive_prefix(path) ? path+2 : path;
78
79 if (slash)
80 while (is_dir_sep(*slash) && slash != start)
81 *slash-- = '\0';
82#else
43 char *slash = last_char_is(path, '/'); 83 char *slash = last_char_is(path, '/');
44 84
45 if (slash) 85 if (slash)
46 while (*slash == '/' && slash != path) 86 while (*slash == '/' && slash != path)
47 *slash-- = '\0'; 87 *slash-- = '\0';
88#endif
48 89
49 return bb_get_last_path_component_nostrip(path); 90 return bb_get_last_path_component_nostrip(path);
50} 91}
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 903ff1fb6..2142ec94c 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -16,7 +16,11 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end)
16 size_t idx = 0; 16 size_t idx = 0;
17 char *linebuf = NULL; 17 char *linebuf = NULL;
18 18
19#if ENABLE_PLATFORM_MINGW32
20 while ((ch = _getc_nolock(file)) != EOF) {
21#else
19 while ((ch = getc(file)) != EOF) { 22 while ((ch = getc(file)) != EOF) {
23#endif
20 /* grow the line buffer as necessary */ 24 /* grow the line buffer as necessary */
21 if (!(idx & 0xff)) { 25 if (!(idx & 0xff)) {
22 if (idx == ((size_t)-1) - 0xff) 26 if (idx == ((size_t)-1) - 0xff)
@@ -41,6 +45,11 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end)
41 linebuf = xrealloc(linebuf, idx + 1); 45 linebuf = xrealloc(linebuf, idx + 1);
42 linebuf[idx] = '\0'; 46 linebuf[idx] = '\0';
43 } 47 }
48#if ENABLE_PLATFORM_MINGW32
49 if (idx && isatty(fileno(file)) &&
50 GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
51 conToCharBuffA(linebuf, idx);
52#endif
44 return linebuf; 53 return linebuf;
45} 54}
46 55
@@ -57,8 +66,17 @@ char* FAST_FUNC xmalloc_fgetline(FILE *file)
57 size_t i; 66 size_t i;
58 char *c = bb_get_chunk_from_file(file, &i); 67 char *c = bb_get_chunk_from_file(file, &i);
59 68
69#if !ENABLE_PLATFORM_MINGW32
60 if (i && c[--i] == '\n') 70 if (i && c[--i] == '\n')
61 c[i] = '\0'; 71 c[i] = '\0';
72#else
73 if (i && c[--i] == '\n') {
74 c[i] = '\0';
75 if (i && c[--i] == '\r') {
76 c[i] = '\0';
77 }
78 }
79#endif
62 80
63 return c; 81 return c;
64} 82}
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index b5efa19ac..76d29d5eb 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -592,7 +592,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
592 return (int32_t)-1; 592 return (int32_t)-1;
593} 593}
594 594
595uint32_t FAST_FUNC 595uint32_t
596getopt32(char **argv, const char *applet_opts, ...) 596getopt32(char **argv, const char *applet_opts, ...)
597{ 597{
598 uint32_t opt; 598 uint32_t opt;
@@ -605,7 +605,7 @@ getopt32(char **argv, const char *applet_opts, ...)
605} 605}
606 606
607#if ENABLE_LONG_OPTS 607#if ENABLE_LONG_OPTS
608uint32_t FAST_FUNC 608uint32_t
609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...) 609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...)
610{ 610{
611 uint32_t opt; 611 uint32_t opt;
diff --git a/libbb/hash_hmac.c b/libbb/hash_hmac.c
new file mode 100644
index 000000000..b3138029f
--- /dev/null
+++ b/libbb/hash_hmac.c
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 2025 Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6//kbuild:lib-$(CONFIG_TLS) += hash_hmac.o
7//kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += hash_hmac.o
8
9#include "libbb.h"
10
11// RFC 2104:
12// HMAC(key, text) based on a hash H (say, sha256) is:
13// ipad = [0x36 x INSIZE]
14// opad = [0x5c x INSIZE]
15// HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text))
16//
17// H(key XOR opad) and H(key XOR ipad) can be precomputed
18// if we often need HMAC hmac with the same key.
19//
20// text is often given in disjoint pieces.
21#if !ENABLE_FEATURE_USE_CNG_API
22void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin)
23{
24#if HMAC_ONLY_SHA256
25#define begin sha256_begin
26#endif
27 uint8_t key_xor_ipad[SHA2_INSIZE];
28 uint8_t key_xor_opad[SHA2_INSIZE];
29 unsigned i;
30
31 // "The authentication key can be of any length up to INSIZE, the
32 // block length of the hash function. Applications that use keys longer
33 // than INSIZE bytes will first hash the key using H and then use the
34 // resultant OUTSIZE byte string as the actual key to HMAC."
35 if (key_size > SHA2_INSIZE) {
36 uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE];
37 /* use ctx->hashed_key_xor_ipad as scratch ctx */
38 begin(&ctx->hashed_key_xor_ipad);
39 md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size);
40 key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey);
41 key = tempkey;
42 }
43
44 for (i = 0; i < key_size; i++) {
45 key_xor_ipad[i] = key[i] ^ 0x36;
46 key_xor_opad[i] = key[i] ^ 0x5c;
47 }
48 for (; i < SHA2_INSIZE; i++) {
49 key_xor_ipad[i] = 0x36;
50 key_xor_opad[i] = 0x5c;
51 }
52
53 begin(&ctx->hashed_key_xor_ipad);
54 begin(&ctx->hashed_key_xor_opad);
55 md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE);
56 md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE);
57}
58#undef begin
59
60unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out)
61{
62 unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out);
63 /* out = H((key XOR opad) + out) */
64 md5sha_hash(&ctx->hashed_key_xor_opad, out, len);
65 return sha_end(&ctx->hashed_key_xor_opad, out);
66}
67
68unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out)
69{
70 hmac_ctx_t ctx;
71 hmac_begin(&ctx, key, key_size, begin);
72 hmac_hash(&ctx, in, sz);
73 return hmac_end(&ctx, out);
74}
75
76/* TLS helpers */
77
78void FAST_FUNC hmac_hash_v(
79 hmac_ctx_t *ctx,
80 va_list va)
81{
82 uint8_t *in;
83
84 /* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
85 /* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
86
87 /* calculate out = H((key XOR ipad) + text) */
88 while ((in = va_arg(va, uint8_t*)) != NULL) {
89 unsigned size = va_arg(va, unsigned);
90 md5sha_hash(&ctx->hashed_key_xor_ipad, in, size);
91 }
92}
93#else
94void _hmac_begin(hmac_ctx_t *ctx, uint8_t *key, unsigned key_size,
95 BCRYPT_ALG_HANDLE alg_handle) {
96 DWORD hash_object_length = 0;
97 ULONG _unused;
98 NTSTATUS status;
99
100 status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH,
101 (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0);
102 mingw_die_if_error(status, "BCryptGetProperty");
103 status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH,
104 (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0);
105 mingw_die_if_error(status, "BCryptGetProperty");
106
107 ctx->hash_obj = xmalloc(hash_object_length);
108
109 status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj,
110 hash_object_length, key, key_size, BCRYPT_HASH_REUSABLE_FLAG);
111 mingw_die_if_error(status, "BCryptCreateHash");
112}
113
114unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out)
115{
116 NTSTATUS status;
117
118 status = BCryptFinishHash(ctx->handle, out, ctx->output_size, 0);
119 mingw_die_if_error(status, "BCryptFinishHash");
120
121 return ctx->output_size;
122}
123
124void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va)
125{
126 uint8_t *in;
127
128 while ((in = va_arg(va, uint8_t*)) != NULL) {
129 unsigned size = va_arg(va, unsigned);
130 BCryptHashData(ctx->handle, in, size, 0);
131 }
132}
133
134void hmac_uninit(hmac_ctx_t *ctx) {
135 BCryptDestroyHash(ctx->handle);
136 free(ctx->hash_obj);
137}
138#endif
139
140/* Using HMAC state, make a copy of it (IOW: without affecting this state!)
141 * hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer.
142 * This function is useful for TLS PRF.
143 */
144unsigned hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...)
145{
146 hmac_ctx_t tmpctx = *ctx; /* struct copy */
147 va_list va;
148
149 va_start(va, out);
150 hmac_hash_v(&tmpctx, va);
151 va_end(va);
152
153 return hmac_end(&tmpctx, out);
154}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 75a61c32c..22dd890bf 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -13,6 +13,82 @@
13 13
14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) 14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA)
15 15
16#if ENABLE_FEATURE_USE_CNG_API
17# include <windows.h>
18# include <bcrypt.h>
19
20// these work on Windows >= 10
21# define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021)
22# define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031)
23# define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041)
24# define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061)
25
26/* Initialize structure containing state of computation.
27 * (RFC 1321, 3.3: Step 3)
28 */
29
30static void generic_init(struct bcrypt_hash_ctx_t *ctx, BCRYPT_ALG_HANDLE alg_handle) {
31 DWORD hash_object_length = 0;
32 ULONG _unused;
33 NTSTATUS status;
34
35 status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0);
36 mingw_die_if_error(status, "BCryptGetProperty");
37 status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0);
38 mingw_die_if_error(status, "BCryptGetProperty");
39
40
41 ctx->hash_obj = xmalloc(hash_object_length);
42
43 status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj, hash_object_length, NULL, 0, 0);
44 mingw_die_if_error(status, "BCryptCreateHash");
45}
46
47void FAST_FUNC md5_begin(md5_ctx_t *ctx)
48{
49 generic_init(ctx, BCRYPT_MD5_ALG_HANDLE);
50}
51
52void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
53{
54 generic_init(ctx, BCRYPT_SHA1_ALG_HANDLE);
55}
56
57/* Initialize structure containing state of computation.
58 (FIPS 180-2:5.3.2) */
59void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
60{
61 generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE);
62}
63
64#if NEED_SHA512
65/* Initialize structure containing state of computation.
66 (FIPS 180-2:5.3.3) */
67void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
68{
69 generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE);
70}
71#endif /* NEED_SHA512 */
72
73void FAST_FUNC generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len)
74{
75 /*
76 for perf, no error checking here
77 */
78 /*NTSTATUS status = */ BCryptHashData(ctx->handle, (const PUCHAR)buffer, len, 0);
79 // mingw_die_if_error(status, "BCryptHashData");
80}
81
82unsigned FAST_FUNC generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf)
83{
84 NTSTATUS status = BCryptFinishHash(ctx->handle, resbuf, ctx->output_size, 0);
85 mingw_die_if_error(status, "BCryptFinishHash");
86 BCryptDestroyHash(ctx->handle);
87 free(ctx->hash_obj);
88 return ctx->output_size;
89}
90#endif /* !ENABLE_FEATURE_USE_CNG_API */
91
16#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL 92#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL
17# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 93# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
18static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) 94static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
@@ -80,6 +156,7 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n)
80 return (x << n) | (x >> (64 - n)); 156 return (x << n) | (x >> (64 - n));
81} 157}
82 158
159#if !ENABLE_FEATURE_USE_CNG_API
83/* Process the remaining bytes in the buffer */ 160/* Process the remaining bytes in the buffer */
84static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) 161static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
85{ 162{
@@ -1367,6 +1444,7 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
1367 return sizeof(ctx->hash); 1444 return sizeof(ctx->hash);
1368} 1445}
1369#endif /* NEED_SHA512 */ 1446#endif /* NEED_SHA512 */
1447#endif /* !ENABLE_FEATURE_USE_CNG_API */
1370 1448
1371 1449
1372/* 1450/*
diff --git a/libbb/hash_sha256_block.c b/libbb/hash_sha256_block.c
new file mode 100644
index 000000000..3c4366321
--- /dev/null
+++ b/libbb/hash_sha256_block.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2025 Denys Vlasenko
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//kbuild:lib-y += hash_sha256_block.o
10#include "libbb.h"
11
12void FAST_FUNC
13sha256_block(const void *in, size_t len, uint8_t hash[32])
14{
15 sha256_ctx_t ctx;
16 sha256_begin(&ctx);
17 sha256_hash(&ctx, in, len);
18 sha256_end(&ctx, hash);
19}
diff --git a/libbb/hash_sha256_hwaccel_x86-32.S b/libbb/hash_sha256_hwaccel_x86-32.S
index a0e4a571a..8d84055e8 100644
--- a/libbb/hash_sha256_hwaccel_x86-32.S
+++ b/libbb/hash_sha256_hwaccel_x86-32.S
@@ -34,21 +34,21 @@
34#define MSG %xmm0 34#define MSG %xmm0
35#define STATE0 %xmm1 35#define STATE0 %xmm1
36#define STATE1 %xmm2 36#define STATE1 %xmm2
37#define MSGTMP0 %xmm3 37#define MSG0 %xmm3
38#define MSGTMP1 %xmm4 38#define MSG1 %xmm4
39#define MSGTMP2 %xmm5 39#define MSG2 %xmm5
40#define MSGTMP3 %xmm6 40#define MSG3 %xmm6
41 41
42#define XMMTMP %xmm7 42#define XMMTMP %xmm7
43 43
44#define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) 44#define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6))
45 45
46 .balign 8 # allow decoders to fetch at least 2 first insns 46 .balign 8 # allow decoders to fetch at least 2 first insns
47sha256_process_block64_shaNI: 47sha256_process_block64_shaNI:
48 48
49 movu128 76+0*16(%eax), XMMTMP /* ABCD (little-endian dword order) */ 49 movu128 76+0*16(%eax), XMMTMP /* ABCD (shown least-significant-dword-first) */
50 movu128 76+1*16(%eax), STATE1 /* EFGH */ 50 movu128 76+1*16(%eax), STATE1 /* EFGH */
51/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 51/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
52 mova128 STATE1, STATE0 52 mova128 STATE1, STATE0
53 /* --- -------------- ABCD -- EFGH */ 53 /* --- -------------- ABCD -- EFGH */
54 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ 54 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */
@@ -58,190 +58,208 @@ sha256_process_block64_shaNI:
58 mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP 58 mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP
59 movl $K256+8*16, SHA256CONSTANTS 59 movl $K256+8*16, SHA256CONSTANTS
60 60
61// sha256rnds2 instruction uses only lower 64 bits of MSG.
62// The code below needs to move upper 64 bits to lower 64 bits
63// for the second sha256rnds2 invocation
64// (what remains in upper bits does not matter).
65// There are several ways to do it:
66// movhlps MSG, MSG // abcd -> cdcd (3 bytes of code)
67// shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes)
68// punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes)
69// unpckhpd MSG, MSG // abcd -> cdcd (4 bytes)
70// psrldq $8, MSG // abcd -> cd00 (5 bytes)
71// palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn)
72#define MOVE_UPPER64_DOWN(reg) movhlps reg, reg
73//#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg
74//#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg
75//#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg
76//#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg
77//#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg
78
61 /* Rounds 0-3 */ 79 /* Rounds 0-3 */
62 movu128 0*16(DATA_PTR), MSG 80 movu128 0*16(DATA_PTR), MSG
63 pshufb XMMTMP, MSG 81 pshufb XMMTMP, MSG
64 mova128 MSG, MSGTMP0 82 mova128 MSG, MSG0
65 paddd 0*16-8*16(SHA256CONSTANTS), MSG 83 paddd 0*16-8*16(SHA256CONSTANTS), MSG
66 sha256rnds2 MSG, STATE0, STATE1 84 sha256rnds2 MSG, STATE0, STATE1
67 shuf128_32 $0x0E, MSG, MSG 85 MOVE_UPPER64_DOWN(MSG)
68 sha256rnds2 MSG, STATE1, STATE0 86 sha256rnds2 MSG, STATE1, STATE0
69 87
70 /* Rounds 4-7 */ 88 /* Rounds 4-7 */
71 movu128 1*16(DATA_PTR), MSG 89 movu128 1*16(DATA_PTR), MSG
72 pshufb XMMTMP, MSG 90 pshufb XMMTMP, MSG
73 mova128 MSG, MSGTMP1 91 mova128 MSG, MSG1
74 paddd 1*16-8*16(SHA256CONSTANTS), MSG 92 paddd 1*16-8*16(SHA256CONSTANTS), MSG
75 sha256rnds2 MSG, STATE0, STATE1 93 sha256rnds2 MSG, STATE0, STATE1
76 shuf128_32 $0x0E, MSG, MSG 94 MOVE_UPPER64_DOWN(MSG)
77 sha256rnds2 MSG, STATE1, STATE0 95 sha256rnds2 MSG, STATE1, STATE0
78 sha256msg1 MSGTMP1, MSGTMP0 96 sha256msg1 MSG1, MSG0
79 97
80 /* Rounds 8-11 */ 98 /* Rounds 8-11 */
81 movu128 2*16(DATA_PTR), MSG 99 movu128 2*16(DATA_PTR), MSG
82 pshufb XMMTMP, MSG 100 pshufb XMMTMP, MSG
83 mova128 MSG, MSGTMP2 101 mova128 MSG, MSG2
84 paddd 2*16-8*16(SHA256CONSTANTS), MSG 102 paddd 2*16-8*16(SHA256CONSTANTS), MSG
85 sha256rnds2 MSG, STATE0, STATE1 103 sha256rnds2 MSG, STATE0, STATE1
86 shuf128_32 $0x0E, MSG, MSG 104 MOVE_UPPER64_DOWN(MSG)
87 sha256rnds2 MSG, STATE1, STATE0 105 sha256rnds2 MSG, STATE1, STATE0
88 sha256msg1 MSGTMP2, MSGTMP1 106 sha256msg1 MSG2, MSG1
89 107
90 /* Rounds 12-15 */ 108 /* Rounds 12-15 */
91 movu128 3*16(DATA_PTR), MSG 109 movu128 3*16(DATA_PTR), MSG
92 pshufb XMMTMP, MSG 110 pshufb XMMTMP, MSG
93/* ...to here */ 111/* ...to here */
94 mova128 MSG, MSGTMP3 112 mova128 MSG, MSG3
95 paddd 3*16-8*16(SHA256CONSTANTS), MSG 113 paddd 3*16-8*16(SHA256CONSTANTS), MSG
96 sha256rnds2 MSG, STATE0, STATE1 114 sha256rnds2 MSG, STATE0, STATE1
97 mova128 MSGTMP3, XMMTMP 115 mova128 MSG3, XMMTMP
98 palignr $4, MSGTMP2, XMMTMP 116 palignr $4, MSG2, XMMTMP
99 paddd XMMTMP, MSGTMP0 117 paddd XMMTMP, MSG0
100 sha256msg2 MSGTMP3, MSGTMP0 118 sha256msg2 MSG3, MSG0
101 shuf128_32 $0x0E, MSG, MSG 119 MOVE_UPPER64_DOWN(MSG)
102 sha256rnds2 MSG, STATE1, STATE0 120 sha256rnds2 MSG, STATE1, STATE0
103 sha256msg1 MSGTMP3, MSGTMP2 121 sha256msg1 MSG3, MSG2
104 122
105 /* Rounds 16-19 */ 123 /* Rounds 16-19 */
106 mova128 MSGTMP0, MSG 124 mova128 MSG0, MSG
107 paddd 4*16-8*16(SHA256CONSTANTS), MSG 125 paddd 4*16-8*16(SHA256CONSTANTS), MSG
108 sha256rnds2 MSG, STATE0, STATE1 126 sha256rnds2 MSG, STATE0, STATE1
109 mova128 MSGTMP0, XMMTMP 127 mova128 MSG0, XMMTMP
110 palignr $4, MSGTMP3, XMMTMP 128 palignr $4, MSG3, XMMTMP
111 paddd XMMTMP, MSGTMP1 129 paddd XMMTMP, MSG1
112 sha256msg2 MSGTMP0, MSGTMP1 130 sha256msg2 MSG0, MSG1
113 shuf128_32 $0x0E, MSG, MSG 131 MOVE_UPPER64_DOWN(MSG)
114 sha256rnds2 MSG, STATE1, STATE0 132 sha256rnds2 MSG, STATE1, STATE0
115 sha256msg1 MSGTMP0, MSGTMP3 133 sha256msg1 MSG0, MSG3
116 134
117 /* Rounds 20-23 */ 135 /* Rounds 20-23 */
118 mova128 MSGTMP1, MSG 136 mova128 MSG1, MSG
119 paddd 5*16-8*16(SHA256CONSTANTS), MSG 137 paddd 5*16-8*16(SHA256CONSTANTS), MSG
120 sha256rnds2 MSG, STATE0, STATE1 138 sha256rnds2 MSG, STATE0, STATE1
121 mova128 MSGTMP1, XMMTMP 139 mova128 MSG1, XMMTMP
122 palignr $4, MSGTMP0, XMMTMP 140 palignr $4, MSG0, XMMTMP
123 paddd XMMTMP, MSGTMP2 141 paddd XMMTMP, MSG2
124 sha256msg2 MSGTMP1, MSGTMP2 142 sha256msg2 MSG1, MSG2
125 shuf128_32 $0x0E, MSG, MSG 143 MOVE_UPPER64_DOWN(MSG)
126 sha256rnds2 MSG, STATE1, STATE0 144 sha256rnds2 MSG, STATE1, STATE0
127 sha256msg1 MSGTMP1, MSGTMP0 145 sha256msg1 MSG1, MSG0
128 146
129 /* Rounds 24-27 */ 147 /* Rounds 24-27 */
130 mova128 MSGTMP2, MSG 148 mova128 MSG2, MSG
131 paddd 6*16-8*16(SHA256CONSTANTS), MSG 149 paddd 6*16-8*16(SHA256CONSTANTS), MSG
132 sha256rnds2 MSG, STATE0, STATE1 150 sha256rnds2 MSG, STATE0, STATE1
133 mova128 MSGTMP2, XMMTMP 151 mova128 MSG2, XMMTMP
134 palignr $4, MSGTMP1, XMMTMP 152 palignr $4, MSG1, XMMTMP
135 paddd XMMTMP, MSGTMP3 153 paddd XMMTMP, MSG3
136 sha256msg2 MSGTMP2, MSGTMP3 154 sha256msg2 MSG2, MSG3
137 shuf128_32 $0x0E, MSG, MSG 155 MOVE_UPPER64_DOWN(MSG)
138 sha256rnds2 MSG, STATE1, STATE0 156 sha256rnds2 MSG, STATE1, STATE0
139 sha256msg1 MSGTMP2, MSGTMP1 157 sha256msg1 MSG2, MSG1
140 158
141 /* Rounds 28-31 */ 159 /* Rounds 28-31 */
142 mova128 MSGTMP3, MSG 160 mova128 MSG3, MSG
143 paddd 7*16-8*16(SHA256CONSTANTS), MSG 161 paddd 7*16-8*16(SHA256CONSTANTS), MSG
144 sha256rnds2 MSG, STATE0, STATE1 162 sha256rnds2 MSG, STATE0, STATE1
145 mova128 MSGTMP3, XMMTMP 163 mova128 MSG3, XMMTMP
146 palignr $4, MSGTMP2, XMMTMP 164 palignr $4, MSG2, XMMTMP
147 paddd XMMTMP, MSGTMP0 165 paddd XMMTMP, MSG0
148 sha256msg2 MSGTMP3, MSGTMP0 166 sha256msg2 MSG3, MSG0
149 shuf128_32 $0x0E, MSG, MSG 167 MOVE_UPPER64_DOWN(MSG)
150 sha256rnds2 MSG, STATE1, STATE0 168 sha256rnds2 MSG, STATE1, STATE0
151 sha256msg1 MSGTMP3, MSGTMP2 169 sha256msg1 MSG3, MSG2
152 170
153 /* Rounds 32-35 */ 171 /* Rounds 32-35 */
154 mova128 MSGTMP0, MSG 172 mova128 MSG0, MSG
155 paddd 8*16-8*16(SHA256CONSTANTS), MSG 173 paddd 8*16-8*16(SHA256CONSTANTS), MSG
156 sha256rnds2 MSG, STATE0, STATE1 174 sha256rnds2 MSG, STATE0, STATE1
157 mova128 MSGTMP0, XMMTMP 175 mova128 MSG0, XMMTMP
158 palignr $4, MSGTMP3, XMMTMP 176 palignr $4, MSG3, XMMTMP
159 paddd XMMTMP, MSGTMP1 177 paddd XMMTMP, MSG1
160 sha256msg2 MSGTMP0, MSGTMP1 178 sha256msg2 MSG0, MSG1
161 shuf128_32 $0x0E, MSG, MSG 179 MOVE_UPPER64_DOWN(MSG)
162 sha256rnds2 MSG, STATE1, STATE0 180 sha256rnds2 MSG, STATE1, STATE0
163 sha256msg1 MSGTMP0, MSGTMP3 181 sha256msg1 MSG0, MSG3
164 182
165 /* Rounds 36-39 */ 183 /* Rounds 36-39 */
166 mova128 MSGTMP1, MSG 184 mova128 MSG1, MSG
167 paddd 9*16-8*16(SHA256CONSTANTS), MSG 185 paddd 9*16-8*16(SHA256CONSTANTS), MSG
168 sha256rnds2 MSG, STATE0, STATE1 186 sha256rnds2 MSG, STATE0, STATE1
169 mova128 MSGTMP1, XMMTMP 187 mova128 MSG1, XMMTMP
170 palignr $4, MSGTMP0, XMMTMP 188 palignr $4, MSG0, XMMTMP
171 paddd XMMTMP, MSGTMP2 189 paddd XMMTMP, MSG2
172 sha256msg2 MSGTMP1, MSGTMP2 190 sha256msg2 MSG1, MSG2
173 shuf128_32 $0x0E, MSG, MSG 191 MOVE_UPPER64_DOWN(MSG)
174 sha256rnds2 MSG, STATE1, STATE0 192 sha256rnds2 MSG, STATE1, STATE0
175 sha256msg1 MSGTMP1, MSGTMP0 193 sha256msg1 MSG1, MSG0
176 194
177 /* Rounds 40-43 */ 195 /* Rounds 40-43 */
178 mova128 MSGTMP2, MSG 196 mova128 MSG2, MSG
179 paddd 10*16-8*16(SHA256CONSTANTS), MSG 197 paddd 10*16-8*16(SHA256CONSTANTS), MSG
180 sha256rnds2 MSG, STATE0, STATE1 198 sha256rnds2 MSG, STATE0, STATE1
181 mova128 MSGTMP2, XMMTMP 199 mova128 MSG2, XMMTMP
182 palignr $4, MSGTMP1, XMMTMP 200 palignr $4, MSG1, XMMTMP
183 paddd XMMTMP, MSGTMP3 201 paddd XMMTMP, MSG3
184 sha256msg2 MSGTMP2, MSGTMP3 202 sha256msg2 MSG2, MSG3
185 shuf128_32 $0x0E, MSG, MSG 203 MOVE_UPPER64_DOWN(MSG)
186 sha256rnds2 MSG, STATE1, STATE0 204 sha256rnds2 MSG, STATE1, STATE0
187 sha256msg1 MSGTMP2, MSGTMP1 205 sha256msg1 MSG2, MSG1
188 206
189 /* Rounds 44-47 */ 207 /* Rounds 44-47 */
190 mova128 MSGTMP3, MSG 208 mova128 MSG3, MSG
191 paddd 11*16-8*16(SHA256CONSTANTS), MSG 209 paddd 11*16-8*16(SHA256CONSTANTS), MSG
192 sha256rnds2 MSG, STATE0, STATE1 210 sha256rnds2 MSG, STATE0, STATE1
193 mova128 MSGTMP3, XMMTMP 211 mova128 MSG3, XMMTMP
194 palignr $4, MSGTMP2, XMMTMP 212 palignr $4, MSG2, XMMTMP
195 paddd XMMTMP, MSGTMP0 213 paddd XMMTMP, MSG0
196 sha256msg2 MSGTMP3, MSGTMP0 214 sha256msg2 MSG3, MSG0
197 shuf128_32 $0x0E, MSG, MSG 215 MOVE_UPPER64_DOWN(MSG)
198 sha256rnds2 MSG, STATE1, STATE0 216 sha256rnds2 MSG, STATE1, STATE0
199 sha256msg1 MSGTMP3, MSGTMP2 217 sha256msg1 MSG3, MSG2
200 218
201 /* Rounds 48-51 */ 219 /* Rounds 48-51 */
202 mova128 MSGTMP0, MSG 220 mova128 MSG0, MSG
203 paddd 12*16-8*16(SHA256CONSTANTS), MSG 221 paddd 12*16-8*16(SHA256CONSTANTS), MSG
204 sha256rnds2 MSG, STATE0, STATE1 222 sha256rnds2 MSG, STATE0, STATE1
205 mova128 MSGTMP0, XMMTMP 223 mova128 MSG0, XMMTMP
206 palignr $4, MSGTMP3, XMMTMP 224 palignr $4, MSG3, XMMTMP
207 paddd XMMTMP, MSGTMP1 225 paddd XMMTMP, MSG1
208 sha256msg2 MSGTMP0, MSGTMP1 226 sha256msg2 MSG0, MSG1
209 shuf128_32 $0x0E, MSG, MSG 227 MOVE_UPPER64_DOWN(MSG)
210 sha256rnds2 MSG, STATE1, STATE0 228 sha256rnds2 MSG, STATE1, STATE0
211 sha256msg1 MSGTMP0, MSGTMP3 229 sha256msg1 MSG0, MSG3
212 230
213 /* Rounds 52-55 */ 231 /* Rounds 52-55 */
214 mova128 MSGTMP1, MSG 232 mova128 MSG1, MSG
215 paddd 13*16-8*16(SHA256CONSTANTS), MSG 233 paddd 13*16-8*16(SHA256CONSTANTS), MSG
216 sha256rnds2 MSG, STATE0, STATE1 234 sha256rnds2 MSG, STATE0, STATE1
217 mova128 MSGTMP1, XMMTMP 235 mova128 MSG1, XMMTMP
218 palignr $4, MSGTMP0, XMMTMP 236 palignr $4, MSG0, XMMTMP
219 paddd XMMTMP, MSGTMP2 237 paddd XMMTMP, MSG2
220 sha256msg2 MSGTMP1, MSGTMP2 238 sha256msg2 MSG1, MSG2
221 shuf128_32 $0x0E, MSG, MSG 239 MOVE_UPPER64_DOWN(MSG)
222 sha256rnds2 MSG, STATE1, STATE0 240 sha256rnds2 MSG, STATE1, STATE0
223 241
224 /* Rounds 56-59 */ 242 /* Rounds 56-59 */
225 mova128 MSGTMP2, MSG 243 mova128 MSG2, MSG
226 paddd 14*16-8*16(SHA256CONSTANTS), MSG 244 paddd 14*16-8*16(SHA256CONSTANTS), MSG
227 sha256rnds2 MSG, STATE0, STATE1 245 sha256rnds2 MSG, STATE0, STATE1
228 mova128 MSGTMP2, XMMTMP 246 mova128 MSG2, XMMTMP
229 palignr $4, MSGTMP1, XMMTMP 247 palignr $4, MSG1, XMMTMP
230 paddd XMMTMP, MSGTMP3 248 paddd XMMTMP, MSG3
231 sha256msg2 MSGTMP2, MSGTMP3 249 sha256msg2 MSG2, MSG3
232 shuf128_32 $0x0E, MSG, MSG 250 MOVE_UPPER64_DOWN(MSG)
233 sha256rnds2 MSG, STATE1, STATE0 251 sha256rnds2 MSG, STATE1, STATE0
234 252
235 /* Rounds 60-63 */ 253 /* Rounds 60-63 */
236 mova128 MSGTMP3, MSG 254 mova128 MSG3, MSG
237 paddd 15*16-8*16(SHA256CONSTANTS), MSG 255 paddd 15*16-8*16(SHA256CONSTANTS), MSG
238 sha256rnds2 MSG, STATE0, STATE1 256 sha256rnds2 MSG, STATE0, STATE1
239 shuf128_32 $0x0E, MSG, MSG 257 MOVE_UPPER64_DOWN(MSG)
240 sha256rnds2 MSG, STATE1, STATE0 258 sha256rnds2 MSG, STATE1, STATE0
241 259
242 /* Write hash values back in the correct order */ 260 /* Write hash values back in the correct order */
243 mova128 STATE0, XMMTMP 261 mova128 STATE0, XMMTMP
244/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 262/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
245 /* --- -------------- HGDC -- FEBA */ 263 /* --- -------------- HGDC -- FEBA */
246 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ 264 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */
247 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ 265 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */
diff --git a/libbb/hash_sha256_hwaccel_x86-64.S b/libbb/hash_sha256_hwaccel_x86-64.S
index 172c2eae2..ee3abbd1f 100644
--- a/libbb/hash_sha256_hwaccel_x86-64.S
+++ b/libbb/hash_sha256_hwaccel_x86-64.S
@@ -34,24 +34,24 @@
34#define MSG %xmm0 34#define MSG %xmm0
35#define STATE0 %xmm1 35#define STATE0 %xmm1
36#define STATE1 %xmm2 36#define STATE1 %xmm2
37#define MSGTMP0 %xmm3 37#define MSG0 %xmm3
38#define MSGTMP1 %xmm4 38#define MSG1 %xmm4
39#define MSGTMP2 %xmm5 39#define MSG2 %xmm5
40#define MSGTMP3 %xmm6 40#define MSG3 %xmm6
41 41
42#define XMMTMP %xmm7 42#define XMMTMP %xmm7
43 43
44#define SAVE0 %xmm8 44#define SAVE0 %xmm8
45#define SAVE1 %xmm9 45#define SAVE1 %xmm9
46 46
47#define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) 47#define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6))
48 48
49 .balign 8 # allow decoders to fetch at least 2 first insns 49 .balign 8 # allow decoders to fetch at least 2 first insns
50sha256_process_block64_shaNI: 50sha256_process_block64_shaNI:
51 51
52 movu128 80+0*16(%rdi), XMMTMP /* ABCD (little-endian dword order) */ 52 movu128 80+0*16(%rdi), XMMTMP /* ABCD (shown least-significant-dword-first) */
53 movu128 80+1*16(%rdi), STATE1 /* EFGH */ 53 movu128 80+1*16(%rdi), STATE1 /* EFGH */
54/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 54/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
55 mova128 STATE1, STATE0 55 mova128 STATE1, STATE0
56 /* --- -------------- ABCD -- EFGH */ 56 /* --- -------------- ABCD -- EFGH */
57 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ 57 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */
@@ -65,185 +65,203 @@ sha256_process_block64_shaNI:
65 mova128 STATE0, SAVE0 65 mova128 STATE0, SAVE0
66 mova128 STATE1, SAVE1 66 mova128 STATE1, SAVE1
67 67
68// sha256rnds2 instruction uses only lower 64 bits of MSG.
69// The code below needs to move upper 64 bits to lower 64 bits
70// for the second sha256rnds2 invocation
71// (what remains in upper bits does not matter).
72// There are several ways to do it:
73// movhlps MSG, MSG // abcd -> cdcd (3 bytes of code)
74// shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes)
75// punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes)
76// unpckhpd MSG, MSG // abcd -> cdcd (4 bytes)
77// psrldq $8, MSG // abcd -> cd00 (5 bytes)
78// palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn)
79#define MOVE_UPPER64_DOWN(reg) movhlps reg, reg
80//#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg
81//#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg
82//#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg
83//#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg
84//#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg
85
68 /* Rounds 0-3 */ 86 /* Rounds 0-3 */
69 movu128 0*16(DATA_PTR), MSG 87 movu128 0*16(DATA_PTR), MSG
70 pshufb XMMTMP, MSG 88 pshufb XMMTMP, MSG
71 mova128 MSG, MSGTMP0 89 mova128 MSG, MSG0
72 paddd 0*16-8*16(SHA256CONSTANTS), MSG 90 paddd 0*16-8*16(SHA256CONSTANTS), MSG
73 sha256rnds2 MSG, STATE0, STATE1 91 sha256rnds2 MSG, STATE0, STATE1
74 shuf128_32 $0x0E, MSG, MSG 92 MOVE_UPPER64_DOWN(MSG)
75 sha256rnds2 MSG, STATE1, STATE0 93 sha256rnds2 MSG, STATE1, STATE0
76 94
77 /* Rounds 4-7 */ 95 /* Rounds 4-7 */
78 movu128 1*16(DATA_PTR), MSG 96 movu128 1*16(DATA_PTR), MSG
79 pshufb XMMTMP, MSG 97 pshufb XMMTMP, MSG
80 mova128 MSG, MSGTMP1 98 mova128 MSG, MSG1
81 paddd 1*16-8*16(SHA256CONSTANTS), MSG 99 paddd 1*16-8*16(SHA256CONSTANTS), MSG
82 sha256rnds2 MSG, STATE0, STATE1 100 sha256rnds2 MSG, STATE0, STATE1
83 shuf128_32 $0x0E, MSG, MSG 101 MOVE_UPPER64_DOWN(MSG)
84 sha256rnds2 MSG, STATE1, STATE0 102 sha256rnds2 MSG, STATE1, STATE0
85 sha256msg1 MSGTMP1, MSGTMP0 103 sha256msg1 MSG1, MSG0
86 104
87 /* Rounds 8-11 */ 105 /* Rounds 8-11 */
88 movu128 2*16(DATA_PTR), MSG 106 movu128 2*16(DATA_PTR), MSG
89 pshufb XMMTMP, MSG 107 pshufb XMMTMP, MSG
90 mova128 MSG, MSGTMP2 108 mova128 MSG, MSG2
91 paddd 2*16-8*16(SHA256CONSTANTS), MSG 109 paddd 2*16-8*16(SHA256CONSTANTS), MSG
92 sha256rnds2 MSG, STATE0, STATE1 110 sha256rnds2 MSG, STATE0, STATE1
93 shuf128_32 $0x0E, MSG, MSG 111 MOVE_UPPER64_DOWN(MSG)
94 sha256rnds2 MSG, STATE1, STATE0 112 sha256rnds2 MSG, STATE1, STATE0
95 sha256msg1 MSGTMP2, MSGTMP1 113 sha256msg1 MSG2, MSG1
96 114
97 /* Rounds 12-15 */ 115 /* Rounds 12-15 */
98 movu128 3*16(DATA_PTR), MSG 116 movu128 3*16(DATA_PTR), MSG
99 pshufb XMMTMP, MSG 117 pshufb XMMTMP, MSG
100/* ...to here */ 118/* ...to here */
101 mova128 MSG, MSGTMP3 119 mova128 MSG, MSG3
102 paddd 3*16-8*16(SHA256CONSTANTS), MSG 120 paddd 3*16-8*16(SHA256CONSTANTS), MSG
103 sha256rnds2 MSG, STATE0, STATE1 121 sha256rnds2 MSG, STATE0, STATE1
104 mova128 MSGTMP3, XMMTMP 122 mova128 MSG3, XMMTMP
105 palignr $4, MSGTMP2, XMMTMP 123 palignr $4, MSG2, XMMTMP
106 paddd XMMTMP, MSGTMP0 124 paddd XMMTMP, MSG0
107 sha256msg2 MSGTMP3, MSGTMP0 125 sha256msg2 MSG3, MSG0
108 shuf128_32 $0x0E, MSG, MSG 126 MOVE_UPPER64_DOWN(MSG)
109 sha256rnds2 MSG, STATE1, STATE0 127 sha256rnds2 MSG, STATE1, STATE0
110 sha256msg1 MSGTMP3, MSGTMP2 128 sha256msg1 MSG3, MSG2
111 129
112 /* Rounds 16-19 */ 130 /* Rounds 16-19 */
113 mova128 MSGTMP0, MSG 131 mova128 MSG0, MSG
114 paddd 4*16-8*16(SHA256CONSTANTS), MSG 132 paddd 4*16-8*16(SHA256CONSTANTS), MSG
115 sha256rnds2 MSG, STATE0, STATE1 133 sha256rnds2 MSG, STATE0, STATE1
116 mova128 MSGTMP0, XMMTMP 134 mova128 MSG0, XMMTMP
117 palignr $4, MSGTMP3, XMMTMP 135 palignr $4, MSG3, XMMTMP
118 paddd XMMTMP, MSGTMP1 136 paddd XMMTMP, MSG1
119 sha256msg2 MSGTMP0, MSGTMP1 137 sha256msg2 MSG0, MSG1
120 shuf128_32 $0x0E, MSG, MSG 138 MOVE_UPPER64_DOWN(MSG)
121 sha256rnds2 MSG, STATE1, STATE0 139 sha256rnds2 MSG, STATE1, STATE0
122 sha256msg1 MSGTMP0, MSGTMP3 140 sha256msg1 MSG0, MSG3
123 141
124 /* Rounds 20-23 */ 142 /* Rounds 20-23 */
125 mova128 MSGTMP1, MSG 143 mova128 MSG1, MSG
126 paddd 5*16-8*16(SHA256CONSTANTS), MSG 144 paddd 5*16-8*16(SHA256CONSTANTS), MSG
127 sha256rnds2 MSG, STATE0, STATE1 145 sha256rnds2 MSG, STATE0, STATE1
128 mova128 MSGTMP1, XMMTMP 146 mova128 MSG1, XMMTMP
129 palignr $4, MSGTMP0, XMMTMP 147 palignr $4, MSG0, XMMTMP
130 paddd XMMTMP, MSGTMP2 148 paddd XMMTMP, MSG2
131 sha256msg2 MSGTMP1, MSGTMP2 149 sha256msg2 MSG1, MSG2
132 shuf128_32 $0x0E, MSG, MSG 150 MOVE_UPPER64_DOWN(MSG)
133 sha256rnds2 MSG, STATE1, STATE0 151 sha256rnds2 MSG, STATE1, STATE0
134 sha256msg1 MSGTMP1, MSGTMP0 152 sha256msg1 MSG1, MSG0
135 153
136 /* Rounds 24-27 */ 154 /* Rounds 24-27 */
137 mova128 MSGTMP2, MSG 155 mova128 MSG2, MSG
138 paddd 6*16-8*16(SHA256CONSTANTS), MSG 156 paddd 6*16-8*16(SHA256CONSTANTS), MSG
139 sha256rnds2 MSG, STATE0, STATE1 157 sha256rnds2 MSG, STATE0, STATE1
140 mova128 MSGTMP2, XMMTMP 158 mova128 MSG2, XMMTMP
141 palignr $4, MSGTMP1, XMMTMP 159 palignr $4, MSG1, XMMTMP
142 paddd XMMTMP, MSGTMP3 160 paddd XMMTMP, MSG3
143 sha256msg2 MSGTMP2, MSGTMP3 161 sha256msg2 MSG2, MSG3
144 shuf128_32 $0x0E, MSG, MSG 162 MOVE_UPPER64_DOWN(MSG)
145 sha256rnds2 MSG, STATE1, STATE0 163 sha256rnds2 MSG, STATE1, STATE0
146 sha256msg1 MSGTMP2, MSGTMP1 164 sha256msg1 MSG2, MSG1
147 165
148 /* Rounds 28-31 */ 166 /* Rounds 28-31 */
149 mova128 MSGTMP3, MSG 167 mova128 MSG3, MSG
150 paddd 7*16-8*16(SHA256CONSTANTS), MSG 168 paddd 7*16-8*16(SHA256CONSTANTS), MSG
151 sha256rnds2 MSG, STATE0, STATE1 169 sha256rnds2 MSG, STATE0, STATE1
152 mova128 MSGTMP3, XMMTMP 170 mova128 MSG3, XMMTMP
153 palignr $4, MSGTMP2, XMMTMP 171 palignr $4, MSG2, XMMTMP
154 paddd XMMTMP, MSGTMP0 172 paddd XMMTMP, MSG0
155 sha256msg2 MSGTMP3, MSGTMP0 173 sha256msg2 MSG3, MSG0
156 shuf128_32 $0x0E, MSG, MSG 174 MOVE_UPPER64_DOWN(MSG)
157 sha256rnds2 MSG, STATE1, STATE0 175 sha256rnds2 MSG, STATE1, STATE0
158 sha256msg1 MSGTMP3, MSGTMP2 176 sha256msg1 MSG3, MSG2
159 177
160 /* Rounds 32-35 */ 178 /* Rounds 32-35 */
161 mova128 MSGTMP0, MSG 179 mova128 MSG0, MSG
162 paddd 8*16-8*16(SHA256CONSTANTS), MSG 180 paddd 8*16-8*16(SHA256CONSTANTS), MSG
163 sha256rnds2 MSG, STATE0, STATE1 181 sha256rnds2 MSG, STATE0, STATE1
164 mova128 MSGTMP0, XMMTMP 182 mova128 MSG0, XMMTMP
165 palignr $4, MSGTMP3, XMMTMP 183 palignr $4, MSG3, XMMTMP
166 paddd XMMTMP, MSGTMP1 184 paddd XMMTMP, MSG1
167 sha256msg2 MSGTMP0, MSGTMP1 185 sha256msg2 MSG0, MSG1
168 shuf128_32 $0x0E, MSG, MSG 186 MOVE_UPPER64_DOWN(MSG)
169 sha256rnds2 MSG, STATE1, STATE0 187 sha256rnds2 MSG, STATE1, STATE0
170 sha256msg1 MSGTMP0, MSGTMP3 188 sha256msg1 MSG0, MSG3
171 189
172 /* Rounds 36-39 */ 190 /* Rounds 36-39 */
173 mova128 MSGTMP1, MSG 191 mova128 MSG1, MSG
174 paddd 9*16-8*16(SHA256CONSTANTS), MSG 192 paddd 9*16-8*16(SHA256CONSTANTS), MSG
175 sha256rnds2 MSG, STATE0, STATE1 193 sha256rnds2 MSG, STATE0, STATE1
176 mova128 MSGTMP1, XMMTMP 194 mova128 MSG1, XMMTMP
177 palignr $4, MSGTMP0, XMMTMP 195 palignr $4, MSG0, XMMTMP
178 paddd XMMTMP, MSGTMP2 196 paddd XMMTMP, MSG2
179 sha256msg2 MSGTMP1, MSGTMP2 197 sha256msg2 MSG1, MSG2
180 shuf128_32 $0x0E, MSG, MSG 198 MOVE_UPPER64_DOWN(MSG)
181 sha256rnds2 MSG, STATE1, STATE0 199 sha256rnds2 MSG, STATE1, STATE0
182 sha256msg1 MSGTMP1, MSGTMP0 200 sha256msg1 MSG1, MSG0
183 201
184 /* Rounds 40-43 */ 202 /* Rounds 40-43 */
185 mova128 MSGTMP2, MSG 203 mova128 MSG2, MSG
186 paddd 10*16-8*16(SHA256CONSTANTS), MSG 204 paddd 10*16-8*16(SHA256CONSTANTS), MSG
187 sha256rnds2 MSG, STATE0, STATE1 205 sha256rnds2 MSG, STATE0, STATE1
188 mova128 MSGTMP2, XMMTMP 206 mova128 MSG2, XMMTMP
189 palignr $4, MSGTMP1, XMMTMP 207 palignr $4, MSG1, XMMTMP
190 paddd XMMTMP, MSGTMP3 208 paddd XMMTMP, MSG3
191 sha256msg2 MSGTMP2, MSGTMP3 209 sha256msg2 MSG2, MSG3
192 shuf128_32 $0x0E, MSG, MSG 210 MOVE_UPPER64_DOWN(MSG)
193 sha256rnds2 MSG, STATE1, STATE0 211 sha256rnds2 MSG, STATE1, STATE0
194 sha256msg1 MSGTMP2, MSGTMP1 212 sha256msg1 MSG2, MSG1
195 213
196 /* Rounds 44-47 */ 214 /* Rounds 44-47 */
197 mova128 MSGTMP3, MSG 215 mova128 MSG3, MSG
198 paddd 11*16-8*16(SHA256CONSTANTS), MSG 216 paddd 11*16-8*16(SHA256CONSTANTS), MSG
199 sha256rnds2 MSG, STATE0, STATE1 217 sha256rnds2 MSG, STATE0, STATE1
200 mova128 MSGTMP3, XMMTMP 218 mova128 MSG3, XMMTMP
201 palignr $4, MSGTMP2, XMMTMP 219 palignr $4, MSG2, XMMTMP
202 paddd XMMTMP, MSGTMP0 220 paddd XMMTMP, MSG0
203 sha256msg2 MSGTMP3, MSGTMP0 221 sha256msg2 MSG3, MSG0
204 shuf128_32 $0x0E, MSG, MSG 222 MOVE_UPPER64_DOWN(MSG)
205 sha256rnds2 MSG, STATE1, STATE0 223 sha256rnds2 MSG, STATE1, STATE0
206 sha256msg1 MSGTMP3, MSGTMP2 224 sha256msg1 MSG3, MSG2
207 225
208 /* Rounds 48-51 */ 226 /* Rounds 48-51 */
209 mova128 MSGTMP0, MSG 227 mova128 MSG0, MSG
210 paddd 12*16-8*16(SHA256CONSTANTS), MSG 228 paddd 12*16-8*16(SHA256CONSTANTS), MSG
211 sha256rnds2 MSG, STATE0, STATE1 229 sha256rnds2 MSG, STATE0, STATE1
212 mova128 MSGTMP0, XMMTMP 230 mova128 MSG0, XMMTMP
213 palignr $4, MSGTMP3, XMMTMP 231 palignr $4, MSG3, XMMTMP
214 paddd XMMTMP, MSGTMP1 232 paddd XMMTMP, MSG1
215 sha256msg2 MSGTMP0, MSGTMP1 233 sha256msg2 MSG0, MSG1
216 shuf128_32 $0x0E, MSG, MSG 234 MOVE_UPPER64_DOWN(MSG)
217 sha256rnds2 MSG, STATE1, STATE0 235 sha256rnds2 MSG, STATE1, STATE0
218 sha256msg1 MSGTMP0, MSGTMP3 236 sha256msg1 MSG0, MSG3
219 237
220 /* Rounds 52-55 */ 238 /* Rounds 52-55 */
221 mova128 MSGTMP1, MSG 239 mova128 MSG1, MSG
222 paddd 13*16-8*16(SHA256CONSTANTS), MSG 240 paddd 13*16-8*16(SHA256CONSTANTS), MSG
223 sha256rnds2 MSG, STATE0, STATE1 241 sha256rnds2 MSG, STATE0, STATE1
224 mova128 MSGTMP1, XMMTMP 242 mova128 MSG1, XMMTMP
225 palignr $4, MSGTMP0, XMMTMP 243 palignr $4, MSG0, XMMTMP
226 paddd XMMTMP, MSGTMP2 244 paddd XMMTMP, MSG2
227 sha256msg2 MSGTMP1, MSGTMP2 245 sha256msg2 MSG1, MSG2
228 shuf128_32 $0x0E, MSG, MSG 246 MOVE_UPPER64_DOWN(MSG)
229 sha256rnds2 MSG, STATE1, STATE0 247 sha256rnds2 MSG, STATE1, STATE0
230 248
231 /* Rounds 56-59 */ 249 /* Rounds 56-59 */
232 mova128 MSGTMP2, MSG 250 mova128 MSG2, MSG
233 paddd 14*16-8*16(SHA256CONSTANTS), MSG 251 paddd 14*16-8*16(SHA256CONSTANTS), MSG
234 sha256rnds2 MSG, STATE0, STATE1 252 sha256rnds2 MSG, STATE0, STATE1
235 mova128 MSGTMP2, XMMTMP 253 mova128 MSG2, XMMTMP
236 palignr $4, MSGTMP1, XMMTMP 254 palignr $4, MSG1, XMMTMP
237 paddd XMMTMP, MSGTMP3 255 paddd XMMTMP, MSG3
238 sha256msg2 MSGTMP2, MSGTMP3 256 sha256msg2 MSG2, MSG3
239 shuf128_32 $0x0E, MSG, MSG 257 MOVE_UPPER64_DOWN(MSG)
240 sha256rnds2 MSG, STATE1, STATE0 258 sha256rnds2 MSG, STATE1, STATE0
241 259
242 /* Rounds 60-63 */ 260 /* Rounds 60-63 */
243 mova128 MSGTMP3, MSG 261 mova128 MSG3, MSG
244 paddd 15*16-8*16(SHA256CONSTANTS), MSG 262 paddd 15*16-8*16(SHA256CONSTANTS), MSG
245 sha256rnds2 MSG, STATE0, STATE1 263 sha256rnds2 MSG, STATE0, STATE1
246 shuf128_32 $0x0E, MSG, MSG 264 MOVE_UPPER64_DOWN(MSG)
247 sha256rnds2 MSG, STATE1, STATE0 265 sha256rnds2 MSG, STATE1, STATE0
248 266
249 /* Add current hash values with previously saved */ 267 /* Add current hash values with previously saved */
@@ -252,7 +270,7 @@ sha256_process_block64_shaNI:
252 270
253 /* Write hash values back in the correct order */ 271 /* Write hash values back in the correct order */
254 mova128 STATE0, XMMTMP 272 mova128 STATE0, XMMTMP
255/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 273/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
256 /* --- -------------- HGDC -- FEBA */ 274 /* --- -------------- HGDC -- FEBA */
257 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ 275 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */
258 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ 276 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c
index a7dd98679..09537ae92 100644
--- a/libbb/herror_msg.c
+++ b/libbb/herror_msg.c
@@ -8,7 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_herror_msg(const char *s, ...) 11void bb_herror_msg(const char *s, ...)
12{ 12{
13 va_list p; 13 va_list p;
14 14
@@ -17,7 +17,7 @@ void FAST_FUNC bb_herror_msg(const char *s, ...)
17 va_end(p); 17 va_end(p);
18} 18}
19 19
20void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) 20void bb_herror_msg_and_die(const char *s, ...)
21{ 21{
22 va_list p; 22 va_list p;
23 23
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
index 09221a186..3199ede6e 100644
--- a/libbb/human_readable.c
+++ b/libbb/human_readable.c
@@ -38,7 +38,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
38 if (val == 0) 38 if (val == 0)
39 return "0"; 39 return "0";
40 40
41 fmt = "%llu"; 41 fmt = "%"LL_FMT"u";
42 if (block_size > 1) 42 if (block_size > 1)
43 val *= block_size; 43 val *= block_size;
44 frac = 0; 44 frac = 0;
@@ -52,7 +52,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
52 while ((val >= 1024) 52 while ((val >= 1024)
53 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */ 53 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */
54 ) { 54 ) {
55 fmt = "%llu.%u%c"; 55 fmt = "%"LL_FMT"u.%u%c";
56 u++; 56 u++;
57 frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024; 57 frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024;
58 val /= 1024; 58 val /= 1024;
@@ -67,7 +67,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
67 if (frac >= 5) { 67 if (frac >= 5) {
68 ++val; 68 ++val;
69 } 69 }
70 fmt = "%llu%*c"; 70 fmt = "%"LL_FMT"u%*c";
71 frac = 1; 71 frac = 1;
72 } 72 }
73#endif 73#endif
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index a125244ca..f2cc417bc 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -61,6 +61,11 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
61 int i; 61 int i;
62 ino_dev_hashtable_bucket_t *bucket; 62 ino_dev_hashtable_bucket_t *bucket;
63 63
64#if ENABLE_FEATURE_EXTRA_FILE_DATA
65 /* ignore invalid inode numbers */
66 if (statbuf->st_ino == 0)
67 return;
68#endif
64 if (!name) 69 if (!name)
65 name = ""; 70 name = "";
66 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); 71 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c
index fba05f974..c2cd92174 100644
--- a/libbb/last_char_is.c
+++ b/libbb/last_char_is.c
@@ -17,3 +17,14 @@ char* FAST_FUNC last_char_is(const char *s, int c)
17 s++; 17 s++;
18 return (*s == (char)c) ? (char *) s : NULL; 18 return (*s == (char)c) ? (char *) s : NULL;
19} 19}
20
21#if ENABLE_PLATFORM_MINGW32
22char* FAST_FUNC last_char_is_dir_sep(const char *s)
23{
24 if (!s[0])
25 return NULL;
26 while (s[1])
27 s++;
28 return is_dir_sep(*s)? (char *) s : NULL;
29}
30#endif
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 151208c1c..c8a0f37fe 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -258,8 +258,14 @@ static NOINLINE const char *get_homedir_or_NULL(void)
258# else 258# else
259 home = getenv("HOME"); 259 home = getenv("HOME");
260# endif 260# endif
261 if (home != NULL && home[0] != '\0') 261 if (home != NULL && home[0] != '\0') {
262# if ENABLE_PLATFORM_MINGW32
263 char *t = auto_string(xstrdup(home));
264 bs_to_slash(t);
265 home = t;
266# endif
262 return home; 267 return home;
268 }
263 269
264 if (!got_user_strings) 270 if (!got_user_strings)
265 get_user_strings(); 271 get_user_strings();
@@ -413,7 +419,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
413/* Put 'command_ps[cursor]', cursor++. 419/* Put 'command_ps[cursor]', cursor++.
414 * Advance cursor on screen. If we reached right margin, scroll text up 420 * Advance cursor on screen. If we reached right margin, scroll text up
415 * and remove terminal margin effect by printing 'next_char' */ 421 * and remove terminal margin effect by printing 'next_char' */
416#define HACK_FOR_WRONG_WIDTH 1 422#define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32
417static void put_cur_glyph_and_inc_cursor(void) 423static void put_cur_glyph_and_inc_cursor(void)
418{ 424{
419 CHAR_T c = command_ps[cursor]; 425 CHAR_T c = command_ps[cursor];
@@ -451,7 +457,7 @@ static void put_cur_glyph_and_inc_cursor(void)
451 * have automargin (IOW: it is moving cursor to next line 457 * have automargin (IOW: it is moving cursor to next line
452 * by itself (which is wrong for VT-10x terminals)), 458 * by itself (which is wrong for VT-10x terminals)),
453 * this will break things: there will be one extra empty line */ 459 * this will break things: there will be one extra empty line */
454 puts("\r"); /* + implicit '\n' */ 460 fputs("\r\n", stderr);
455#else 461#else
456 /* VT-10x terminals don't wrap cursor to next line when last char 462 /* VT-10x terminals don't wrap cursor to next line when last char
457 * on the line is printed - cursor stays "over" this char. 463 * on the line is printed - cursor stays "over" this char.
@@ -476,6 +482,42 @@ static void put_cur_glyph_and_inc_cursor(void)
476 } 482 }
477} 483}
478 484
485#if ENABLE_PLATFORM_MINGW32
486static void inc_cursor(void)
487{
488 CHAR_T c = command_ps[cursor];
489 unsigned width = 0;
490 int ofs_to_right;
491
492 /* advance cursor */
493 cursor++;
494 if (unicode_status == UNICODE_ON) {
495 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
496 c = adjust_width_and_validate_wc(&cmdedit_x, c);
497 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
498 } else {
499 cmdedit_x++;
500 }
501
502 ofs_to_right = cmdedit_x - cmdedit_termw;
503 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
504 /* cursor remains on this line */
505 printf(ESC"[1C");
506 }
507
508 if (ofs_to_right >= 0) {
509 /* we go to the next line */
510 printf(ESC"[1B");
511 bb_putchar('\r');
512 cmdedit_y++;
513 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
514 width = 0;
515 }
516 cmdedit_x = width;
517 }
518}
519#endif
520
479/* Move to end of line (by printing all chars till the end) */ 521/* Move to end of line (by printing all chars till the end) */
480static void put_till_end_and_adv_cursor(void) 522static void put_till_end_and_adv_cursor(void)
481{ 523{
@@ -538,6 +580,7 @@ static void input_backward(unsigned num)
538 580
539 if (cmdedit_x >= num) { 581 if (cmdedit_x >= num) {
540 cmdedit_x -= num; 582 cmdedit_x -= num;
583#if !ENABLE_PLATFORM_MINGW32
541 if (num <= 4) { 584 if (num <= 4) {
542 /* This is longer by 5 bytes on x86. 585 /* This is longer by 5 bytes on x86.
543 * Also gets miscompiled for ARM users 586 * Also gets miscompiled for ARM users
@@ -550,6 +593,7 @@ static void input_backward(unsigned num)
550 } while (--num); 593 } while (--num);
551 return; 594 return;
552 } 595 }
596#endif
553 fprintf(stderr, ESC"[%uD", num); 597 fprintf(stderr, ESC"[%uD", num);
554 return; 598 return;
555 } 599 }
@@ -688,7 +732,23 @@ static void input_backspace(void)
688static void input_forward(void) 732static void input_forward(void)
689{ 733{
690 if (cursor < command_len) 734 if (cursor < command_len)
735#if !ENABLE_PLATFORM_MINGW32
691 put_cur_glyph_and_inc_cursor(); 736 put_cur_glyph_and_inc_cursor();
737#else
738 /*
739 * inc_cursor improves forward cursor movement appearance on
740 * win 7/8 console, but it's broken with unicode wide-glyphs,
741 * e.g. paste and move forward over: echo 开开心心过每一天
742 * so disable inc_cursor when unicode is active (which is only
743 * windows 10+, where inc_cursor is not needed anyway).
744 */
745 {
746 if (unicode_status == UNICODE_ON)
747 put_cur_glyph_and_inc_cursor();
748 else
749 inc_cursor();
750 }
751#endif
692} 752}
693 753
694#if ENABLE_FEATURE_TAB_COMPLETION 754#if ENABLE_FEATURE_TAB_COMPLETION
@@ -709,25 +769,56 @@ static void free_tab_completion_data(void)
709 } 769 }
710} 770}
711 771
712static void add_match(char *matched) 772#if !ENABLE_PLATFORM_MINGW32
773# define add_match(m, s) add_match(m)
774#endif
775
776static void add_match(char *matched, int sensitive)
713{ 777{
778# if ENABLE_PLATFORM_MINGW32
779 size_t len;
780# endif
714 unsigned char *p = (unsigned char*)matched; 781 unsigned char *p = (unsigned char*)matched;
715 while (*p) { 782 while (*p) {
716 /* ESC attack fix: drop any string with control chars */ 783 /* ESC attack fix: drop any string with control chars */
717 if (*p < ' ' 784 if (*p < ' '
785# if !ENABLE_PLATFORM_MINGW32
718 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f) 786 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f)
719 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f) 787 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f)
788# else
789 /*
790 * on Windows, *p > 0x7f is never control:
791 * without unicode active: these are normal codepage chars.
792 * with unicode active: these are UTF8 continuation bytes.
793 */
794 || *p == 0x7f
795# endif
720 ) { 796 ) {
721 free(matched); 797 free(matched);
722 return; 798 return;
723 } 799 }
724 p++; 800 p++;
725 } 801 }
802# if ENABLE_PLATFORM_MINGW32
803 /* The case-sensitivity flag is stored after NUL terminator */
804 len = strlen(matched);
805 matched = xrealloc(matched, len + 2);
806 matched[len + 1] = sensitive;
807# endif
726 matches = xrealloc_vector(matches, 4, num_matches); 808 matches = xrealloc_vector(matches, 4, num_matches);
727 matches[num_matches] = matched; 809 matches[num_matches] = matched;
728 num_matches++; 810 num_matches++;
729} 811}
730 812
813# if ENABLE_PLATFORM_MINGW32
814static int is_case_sensitive(const char *p)
815{
816 while (*p++)
817 ;
818 return *p;
819}
820# endif
821
731# if ENABLE_FEATURE_USERNAME_COMPLETION 822# if ENABLE_FEATURE_USERNAME_COMPLETION
732/* Replace "~user/..." with "/homedir/...". 823/* Replace "~user/..." with "/homedir/...".
733 * The parameter is malloced, free it or return it 824 * The parameter is malloced, free it or return it
@@ -735,13 +826,16 @@ static void add_match(char *matched)
735 */ 826 */
736static char *username_path_completion(char *ud) 827static char *username_path_completion(char *ud)
737{ 828{
829# if !ENABLE_PLATFORM_MINGW32
738 struct passwd *entry; 830 struct passwd *entry;
831#endif
739 char *tilde_name = ud; 832 char *tilde_name = ud;
740 const char *home = NULL; 833 const char *home = NULL;
741 834
742 ud++; /* skip ~ */ 835 ud++; /* skip ~ */
743 if (*ud == '/') { /* "~/..." */ 836 if (*ud == '/') { /* "~/..." */
744 home = get_homedir_or_NULL(); 837 home = get_homedir_or_NULL();
838# if !ENABLE_PLATFORM_MINGW32
745 } else { 839 } else {
746 /* "~user/..." */ 840 /* "~user/..." */
747 ud = strchr(ud, '/'); 841 ud = strchr(ud, '/');
@@ -750,6 +844,7 @@ static char *username_path_completion(char *ud)
750 *ud = '/'; /* restore "~user/..." */ 844 *ud = '/'; /* restore "~user/..." */
751 if (entry) 845 if (entry)
752 home = entry->pw_dir; 846 home = entry->pw_dir;
847# endif
753 } 848 }
754 if (home) { 849 if (home) {
755 ud = concat_path_file(home, ud); 850 ud = concat_path_file(home, ud);
@@ -759,6 +854,7 @@ static char *username_path_completion(char *ud)
759 return tilde_name; 854 return tilde_name;
760} 855}
761 856
857# if !ENABLE_PLATFORM_MINGW32
762/* ~use<tab> - find all users with this prefix. 858/* ~use<tab> - find all users with this prefix.
763 * Return the length of the prefix used for matching. 859 * Return the length of the prefix used for matching.
764 */ 860 */
@@ -774,13 +870,14 @@ static NOINLINE unsigned complete_username(const char *ud)
774 while ((pw = getpwent()) != NULL) { 870 while ((pw = getpwent()) != NULL) {
775 /* Null usernames should result in all users as possible completions. */ 871 /* Null usernames should result in all users as possible completions. */
776 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) { 872 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) {
777 add_match(xasprintf("~%s/", pw->pw_name)); 873 add_match(xasprintf("~%s/", pw->pw_name), TRUE);
778 } 874 }
779 } 875 }
780 endpwent(); /* don't keep password file open */ 876 endpwent(); /* don't keep password file open */
781 877
782 return 1 + userlen; 878 return 1 + userlen;
783} 879}
880# endif
784# endif /* FEATURE_USERNAME_COMPLETION */ 881# endif /* FEATURE_USERNAME_COMPLETION */
785 882
786enum { 883enum {
@@ -810,7 +907,7 @@ static unsigned path_parse(char ***p)
810 tmp = (char*)pth; 907 tmp = (char*)pth;
811 npth = 1; /* path component count */ 908 npth = 1; /* path component count */
812 while (1) { 909 while (1) {
813 tmp = strchr(tmp, ':'); 910 tmp = strchr(tmp, PATH_SEP);
814 if (!tmp) 911 if (!tmp)
815 break; 912 break;
816 tmp++; 913 tmp++;
@@ -821,7 +918,7 @@ static unsigned path_parse(char ***p)
821 res[0] = tmp = xstrdup(pth); 918 res[0] = tmp = xstrdup(pth);
822 npth = 1; 919 npth = 1;
823 while (1) { 920 while (1) {
824 tmp = strchr(tmp, ':'); 921 tmp = strchr(tmp, PATH_SEP);
825 if (!tmp) 922 if (!tmp)
826 break; 923 break;
827 *tmp++ = '\0'; /* ':' -> '\0' */ 924 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -849,6 +946,17 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
849 path1[0] = (char*)"."; 946 path1[0] = (char*)".";
850 947
851 basecmd = strrchr(command, '/'); 948 basecmd = strrchr(command, '/');
949#if ENABLE_PLATFORM_MINGW32
950 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
951 char buffer[PATH_MAX];
952
953 /* path is of form c:path with no '/' */
954 if (get_drive_cwd(command, buffer, PATH_MAX)) {
955 basecmd = command + 2;
956 path1[0] = dirbuf = xstrdup(buffer);
957 }
958 } else
959#endif
852 if (!basecmd) { 960 if (!basecmd) {
853 if (type == FIND_EXE_ONLY) 961 if (type == FIND_EXE_ONLY)
854 npaths = path_parse(&paths); 962 npaths = path_parse(&paths);
@@ -869,9 +977,13 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
869 if (type == FIND_EXE_ONLY && !dirbuf) { 977 if (type == FIND_EXE_ONLY && !dirbuf) {
870# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 978# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
871 const char *p = applet_names; 979 const char *p = applet_names;
980# if ENABLE_PLATFORM_MINGW32
981 const char *shpath = state->flags & WITH_PATH_LOOKUP ?
982 state->path_lookup : NULL;
983# endif
872 while (*p) { 984 while (*p) {
873 if (strncmp(basecmd, p, baselen) == 0) 985 if (strncmp(basecmd, p, baselen) == 0 && prefer_applet(p, shpath))
874 add_match(xstrdup(p)); 986 add_match(xstrdup(p), TRUE);
875 while (*p++ != '\0') 987 while (*p++ != '\0')
876 continue; 988 continue;
877 } 989 }
@@ -884,7 +996,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
884 if (!b) 996 if (!b)
885 break; 997 break;
886 if (strncmp(basecmd, b, baselen) == 0) 998 if (strncmp(basecmd, b, baselen) == 0)
887 add_match(xstrdup(b)); 999 add_match(xstrdup(b), TRUE);
888 } 1000 }
889 } 1001 }
890# endif 1002# endif
@@ -918,7 +1030,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
918 if (!basecmd[0] && DOT_OR_DOTDOT(name_found)) 1030 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
919 continue; 1031 continue;
920 /* match? */ 1032 /* match? */
1033# if ENABLE_PLATFORM_MINGW32
1034 if (strncasecmp(basecmd, name_found, baselen) != 0)
1035# else
921 if (strncmp(basecmd, name_found, baselen) != 0) 1036 if (strncmp(basecmd, name_found, baselen) != 0)
1037# endif
922 continue; /* no */ 1038 continue; /* no */
923 1039
924 found = concat_path_file(lpath, name_found); 1040 found = concat_path_file(lpath, name_found);
@@ -928,6 +1044,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 if (stat(found, &st) && lstat(found, &st)) 1044 if (stat(found, &st) && lstat(found, &st))
929 goto cont; /* hmm, remove in progress? */ 1045 goto cont; /* hmm, remove in progress? */
930 1046
1047# if ENABLE_PLATFORM_MINGW32
1048# if ENABLE_ASH_GLOB_OPTIONS
1049 if (state->sh_accept_glob && !state->sh_accept_glob(found))
1050 goto cont;
1051# endif
1052 if (type == FIND_EXE_ONLY && S_ISREG(st.st_mode) &&
1053 !(st.st_mode & S_IXUSR))
1054 goto cont;
1055# endif
1056
931 /* Save only name */ 1057 /* Save only name */
932 len = strlen(name_found); 1058 len = strlen(name_found);
933 found = xrealloc(found, len + 2); /* +2: for slash and NUL */ 1059 found = xrealloc(found, len + 2); /* +2: for slash and NUL */
@@ -946,7 +1072,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
946 goto cont; 1072 goto cont;
947 } 1073 }
948 /* add it to the list */ 1074 /* add it to the list */
949 add_match(found); 1075 add_match(found, FALSE);
950 continue; 1076 continue;
951 cont: 1077 cont:
952 free(found); 1078 free(found);
@@ -1011,7 +1137,13 @@ static NOINLINE int build_match_prefix(char *match_buf)
1011 1137
1012 /* Mark every \c as "quoted c" */ 1138 /* Mark every \c as "quoted c" */
1013 for (i = 0; int_buf[i]; i++) { 1139 for (i = 0; int_buf[i]; i++) {
1140#if ENABLE_PLATFORM_MINGW32
1141 /* Trailing backslash is effectively removed which confuses
1142 * the code to display case-preserved filenames. */
1143 if (int_buf[i] == '\\' && int_buf[i+1] != '\0') {
1144#else
1014 if (int_buf[i] == '\\') { 1145 if (int_buf[i] == '\\') {
1146#endif
1015 remove_chunk(int_buf, i, i + 1); 1147 remove_chunk(int_buf, i, i + 1);
1016 int_buf[i] |= QUOT; 1148 int_buf[i] |= QUOT;
1017 } 1149 }
@@ -1170,9 +1302,10 @@ static void showfiles(void)
1170 ); 1302 );
1171 } 1303 }
1172 if (ENABLE_UNICODE_SUPPORT) 1304 if (ENABLE_UNICODE_SUPPORT)
1173 puts(printable_string(matches[n])); 1305 fputs(printable_string(matches[n]), stderr);
1174 else 1306 else
1175 puts(matches[n]); 1307 fputs(matches[n], stderr);
1308 bb_putchar_stderr('\n');
1176 } 1309 }
1177} 1310}
1178 1311
@@ -1212,6 +1345,25 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1212 size_t len_found; 1345 size_t len_found;
1213 /* Length of string used for matching */ 1346 /* Length of string used for matching */
1214 unsigned match_pfx_len = match_pfx_len; 1347 unsigned match_pfx_len = match_pfx_len;
1348# if ENABLE_PLATFORM_MINGW32
1349 int chosen_index = 0;
1350 int chosen_sens = FALSE;
1351# if !ENABLE_UNICODE_SUPPORT
1352 /*
1353 * FIXME: the next three vars are unused with ENABLE_UNICODE_SUPPORT
1354 * because the mingw code which uses them to update a tab-completion
1355 * prefix to the correct case (e.g. ~/desk<tab> to ~/Desktop/) is
1356 * not compiled, and so e.g. ~/desk<tab> completes to ~/desktop/ .
1357 */
1358 unsigned orig_pfx_len;
1359 char *target;
1360 const char *source;
1361# endif
1362# define first_match 0
1363# else
1364# define chosen_index 0
1365# define first_match 1
1366# endif
1215 int find_type; 1367 int find_type;
1216# if ENABLE_UNICODE_SUPPORT 1368# if ENABLE_UNICODE_SUPPORT
1217 /* cursor pos in command converted to multibyte form */ 1369 /* cursor pos in command converted to multibyte form */
@@ -1259,7 +1411,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1259 /* Free up any memory already allocated */ 1411 /* Free up any memory already allocated */
1260 free_tab_completion_data(); 1412 free_tab_completion_data();
1261 1413
1262# if ENABLE_FEATURE_USERNAME_COMPLETION 1414# if ENABLE_FEATURE_USERNAME_COMPLETION && !ENABLE_PLATFORM_MINGW32
1263 /* If the word starts with ~ and there is no slash in the word, 1415 /* If the word starts with ~ and there is no slash in the word,
1264 * then try completing this word as a username. */ 1416 * then try completing this word as a username. */
1265 if (state->flags & USERNAME_COMPLETION) 1417 if (state->flags & USERNAME_COMPLETION)
@@ -1276,6 +1428,9 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1276 { 1428 {
1277 const char *e = match_buf + strlen(match_buf); 1429 const char *e = match_buf + strlen(match_buf);
1278 const char *s = e - match_pfx_len; 1430 const char *s = e - match_pfx_len;
1431# if ENABLE_PLATFORM_MINGW32 && !ENABLE_UNICODE_SUPPORT
1432 orig_pfx_len = match_pfx_len;
1433# endif
1279 while (s < e) 1434 while (s < e)
1280 if (is_special_char(*s++)) 1435 if (is_special_char(*s++))
1281 match_pfx_len++; 1436 match_pfx_len++;
@@ -1306,10 +1461,29 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1306 if (!matches) 1461 if (!matches)
1307 goto ret; /* no matches at all */ 1462 goto ret; /* no matches at all */
1308 /* Find common prefix */ 1463 /* Find common prefix */
1309 chosen_match = xstrdup(matches[0]); 1464# if ENABLE_PLATFORM_MINGW32
1465 /* Any comparison involving a filename must be case-insensitive.
1466 * The chosen match should be case-sensitive, if possible */
1467 for (unsigned i = 0; i < num_matches; ++i) {
1468 if (is_case_sensitive(matches[i])) {
1469 chosen_index = i;
1470 chosen_sens = TRUE;
1471 break;
1472 }
1473 }
1474# endif
1475 chosen_match = xstrdup(matches[chosen_index]);
1310 for (cp = chosen_match; *cp; cp++) { 1476 for (cp = chosen_match; *cp; cp++) {
1311 unsigned n; 1477 unsigned n;
1312 for (n = 1; n < num_matches; n++) { 1478 for (n = first_match; n < num_matches; n++) {
1479# if ENABLE_PLATFORM_MINGW32
1480 if (!is_case_sensitive(matches[n]) || !chosen_sens) {
1481 if (tolower(matches[n][cp - chosen_match]) !=
1482 tolower(*cp)) {
1483 goto stop;
1484 }
1485 } else
1486# endif
1313 if (matches[n][cp - chosen_match] != *cp) { 1487 if (matches[n][cp - chosen_match] != *cp) {
1314 goto stop; 1488 goto stop;
1315 } 1489 }
@@ -1346,7 +1520,21 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1346 /* save tail */ 1520 /* save tail */
1347 strcpy(match_buf, &command_ps[cursor]); 1521 strcpy(match_buf, &command_ps[cursor]);
1348 /* add match and tail */ 1522 /* add match and tail */
1523# if ENABLE_PLATFORM_MINGW32
1524 if (match_pfx_len == orig_pfx_len) {
1525 /* replace match prefix to allow for altered case */
1526 target = &command_ps[cursor-match_pfx_len];
1527 source = chosen_match;
1528 }
1529 else {
1530 /* only replace tail of match if special characters are quoted */
1531 target = &command_ps[cursor];
1532 source = chosen_match + match_pfx_len;
1533 }
1534 strcpy(stpcpy(target, source), match_buf);
1535# else
1349 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); 1536 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
1537# endif
1350 command_len = strlen(command_ps); 1538 command_len = strlen(command_ps);
1351 /* new pos */ 1539 /* new pos */
1352 pos = cursor + len_found - match_pfx_len; 1540 pos = cursor + len_found - match_pfx_len;
@@ -1382,7 +1570,6 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1382 free(chosen_match); 1570 free(chosen_match);
1383 free(match_buf); 1571 free(match_buf);
1384} 1572}
1385
1386#endif /* FEATURE_TAB_COMPLETION */ 1573#endif /* FEATURE_TAB_COMPLETION */
1387 1574
1388 1575
@@ -1402,11 +1589,15 @@ line_input_t* FAST_FUNC new_line_input_t(int flags)
1402 1589
1403unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) 1590unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1404{ 1591{
1592# if ENABLE_PLATFORM_MINGW32 && DEFAULT_HISTORY > 0 && DEFAULT_HISTORY <= MAX_HISTORY
1593 int size = DEFAULT_HISTORY;
1594# else
1405 int size = MAX_HISTORY; 1595 int size = MAX_HISTORY;
1596# endif
1406 if (hp) { 1597 if (hp) {
1407 size = atoi(hp); 1598 size = atoi(hp);
1408 if (size <= 0) 1599 if (size < 0)
1409 return 1; 1600 return 0;
1410 if (size > MAX_HISTORY) 1601 if (size > MAX_HISTORY)
1411 return MAX_HISTORY; 1602 return MAX_HISTORY;
1412 } 1603 }
@@ -1500,18 +1691,21 @@ static void load_history(line_input_t *st_parm)
1500 /* NB: do not trash old history if file can't be opened */ 1691 /* NB: do not trash old history if file can't be opened */
1501 1692
1502 fp = fopen_for_read(st_parm->hist_file); 1693 fp = fopen_for_read(st_parm->hist_file);
1503 if (fp) { 1694 if (!fp)
1504 /* clean up old history */ 1695 return;
1505 for (idx = st_parm->cnt_history; idx > 0;) { 1696
1506 idx--; 1697 /* clean up old history */
1507 free(st_parm->history[idx]); 1698 for (idx = st_parm->cnt_history; idx > 0;) {
1508 st_parm->history[idx] = NULL; 1699 idx--;
1509 } 1700 free(st_parm->history[idx]);
1701 st_parm->history[idx] = NULL;
1702 }
1510 1703
1511 /* fill temp_h[], retaining only last MAX_HISTORY lines */ 1704 /* fill temp_h[], retaining only last max_history lines */
1512 memset(temp_h, 0, sizeof(temp_h)); 1705 memset(temp_h, 0, sizeof(temp_h));
1513 idx = 0; 1706 idx = 0;
1514 st_parm->cnt_history_in_file = 0; 1707 st_parm->cnt_history_in_file = 0;
1708 if (st_parm->max_history != 0) {
1515 while ((line = xmalloc_fgetline(fp)) != NULL) { 1709 while ((line = xmalloc_fgetline(fp)) != NULL) {
1516 if (line[0] == '\0') { 1710 if (line[0] == '\0') {
1517 free(line); 1711 free(line);
@@ -1524,34 +1718,34 @@ static void load_history(line_input_t *st_parm)
1524 if (idx == st_parm->max_history) 1718 if (idx == st_parm->max_history)
1525 idx = 0; 1719 idx = 0;
1526 } 1720 }
1527 fclose(fp); 1721 }
1528 1722 fclose(fp);
1529 /* find first non-NULL temp_h[], if any */
1530 if (st_parm->cnt_history_in_file) {
1531 while (temp_h[idx] == NULL) {
1532 idx++;
1533 if (idx == st_parm->max_history)
1534 idx = 0;
1535 }
1536 }
1537 1723
1538 /* copy temp_h[] to st_parm->history[] */ 1724 /* find first non-NULL temp_h[], if any */
1539 for (i = 0; i < st_parm->max_history;) { 1725 if (st_parm->cnt_history_in_file != 0) {
1540 line = temp_h[idx]; 1726 while (temp_h[idx] == NULL) {
1541 if (!line)
1542 break;
1543 idx++; 1727 idx++;
1544 if (idx == st_parm->max_history) 1728 if (idx == st_parm->max_history)
1545 idx = 0; 1729 idx = 0;
1546 line_len = strlen(line);
1547 if (line_len >= MAX_LINELEN)
1548 line[MAX_LINELEN-1] = '\0';
1549 st_parm->history[i++] = line;
1550 } 1730 }
1551 st_parm->cnt_history = i;
1552 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1553 st_parm->cnt_history_in_file = i;
1554 } 1731 }
1732
1733 /* copy temp_h[] to st_parm->history[] */
1734 for (i = 0; i < st_parm->max_history;) {
1735 line = temp_h[idx];
1736 if (!line)
1737 break;
1738 idx++;
1739 if (idx == st_parm->max_history)
1740 idx = 0;
1741 line_len = strlen(line);
1742 if (line_len >= MAX_LINELEN)
1743 line[MAX_LINELEN-1] = '\0';
1744 st_parm->history[i++] = line;
1745 }
1746 st_parm->cnt_history = i;
1747 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1748 st_parm->cnt_history_in_file = i;
1555} 1749}
1556 1750
1557# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1751# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
@@ -1559,17 +1753,27 @@ void FAST_FUNC save_history(line_input_t *st)
1559{ 1753{
1560 FILE *fp; 1754 FILE *fp;
1561 1755
1562 if (!st || !st->hist_file) 1756 /* bash compat: HISTFILE="" disables history saving */
1757 if (!st || !st->hist_file || !state->hist_file[0])
1563 return; 1758 return;
1564 if (st->cnt_history <= st->cnt_history_in_file) 1759 if (st->cnt_history <= st->cnt_history_in_file)
1565 return; 1760 return; /* no new entries were added */
1761 /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */
1566 1762
1567 fp = fopen(st->hist_file, "a"); 1763 fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a"));
1568 if (fp) { 1764 if (fp) {
1569 int i, fd; 1765 int i, fd;
1570 char *new_name; 1766 char *new_name;
1571 line_input_t *st_temp; 1767 line_input_t *st_temp;
1572 1768
1769 /* max_history==0 needs special-casing in general code,
1770 * just handle it in a simpler way: */
1771 if (st->max_history == 0) {
1772 /* fopen("w") already truncated it */
1773 fclose(fp);
1774 return;
1775 }
1776
1573 for (i = st->cnt_history_in_file; i < st->cnt_history; i++) 1777 for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
1574 fprintf(fp, "%s\n", st->history[i]); 1778 fprintf(fp, "%s\n", st->history[i]);
1575 fclose(fp); 1779 fclose(fp);
@@ -1579,6 +1783,8 @@ void FAST_FUNC save_history(line_input_t *st)
1579 st_temp = new_line_input_t(st->flags); 1783 st_temp = new_line_input_t(st->flags);
1580 st_temp->hist_file = st->hist_file; 1784 st_temp->hist_file = st->hist_file;
1581 st_temp->max_history = st->max_history; 1785 st_temp->max_history = st->max_history;
1786 /* load no more than max_history last lines */
1787 /* (in unlikely case that file disappeared, st_temp gets empty history) */
1582 load_history(st_temp); 1788 load_history(st_temp);
1583 1789
1584 /* write out temp file and replace hist_file atomically */ 1790 /* write out temp file and replace hist_file atomically */
@@ -1602,13 +1808,13 @@ static void save_history(char *str)
1602 int fd; 1808 int fd;
1603 int len, len2; 1809 int len, len2;
1604 1810
1605 if (!state->hist_file) 1811 /* bash compat: HISTFILE="" disables history saving */
1812 if (!state->hist_file || !state->hist_file[0])
1606 return; 1813 return;
1607 1814
1608 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); 1815 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1609 if (fd < 0) 1816 if (fd < 0)
1610 return; 1817 return;
1611 xlseek(fd, 0, SEEK_END); /* paranoia */
1612 len = strlen(str); 1818 len = strlen(str);
1613 str[len] = '\n'; /* we (try to) do atomic write */ 1819 str[len] = '\n'; /* we (try to) do atomic write */
1614 len2 = full_write(fd, str, len + 1); 1820 len2 = full_write(fd, str, len + 1);
@@ -1663,13 +1869,10 @@ static void remember_in_history(char *str)
1663 if (str[0] == '\0') 1869 if (str[0] == '\0')
1664 return; 1870 return;
1665 i = state->cnt_history; 1871 i = state->cnt_history;
1666 /* Don't save dupes */ 1872 /* Don't save dups */
1667 if (i && strcmp(state->history[i-1], str) == 0) 1873 if (i != 0 && strcmp(state->history[i-1], str) == 0)
1668 return; 1874 return;
1669 1875
1670 free(state->history[state->max_history]); /* redundant, paranoia */
1671 state->history[state->max_history] = NULL; /* redundant, paranoia */
1672
1673 /* If history[] is full, remove the oldest command */ 1876 /* If history[] is full, remove the oldest command */
1674 /* we need to keep history[state->max_history] empty, hence >=, not > */ 1877 /* we need to keep history[state->max_history] empty, hence >=, not > */
1675 if (i >= state->max_history) { 1878 if (i >= state->max_history) {
@@ -1682,7 +1885,7 @@ static void remember_in_history(char *str)
1682 state->cnt_history_in_file--; 1885 state->cnt_history_in_file--;
1683# endif 1886# endif
1684 } 1887 }
1685 /* i <= state->max_history-1 */ 1888 /* i < state->max_history */
1686 state->history[i++] = xstrdup(str); 1889 state->history[i++] = xstrdup(str);
1687 /* i <= state->max_history */ 1890 /* i <= state->max_history */
1688 state->cur_history = i; 1891 state->cur_history = i;
@@ -2053,7 +2256,11 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2053 char *after_home_user; 2256 char *after_home_user;
2054 2257
2055 /* /home/user[/something] -> ~[/something] */ 2258 /* /home/user[/something] -> ~[/something] */
2259#if !ENABLE_PLATFORM_MINGW32
2056 after_home_user = is_prefixed_with(cwd_buf, home); 2260 after_home_user = is_prefixed_with(cwd_buf, home);
2261#else
2262 after_home_user = is_prefixed_with_case(cwd_buf, home);
2263#endif
2057 if (after_home_user 2264 if (after_home_user
2058 && (*after_home_user == '/' || *after_home_user == '\0') 2265 && (*after_home_user == '/' || *after_home_user == '\0')
2059 ) { 2266 ) {
@@ -2194,7 +2401,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2194 errno = EINTR; 2401 errno = EINTR;
2195 return -1; 2402 return -1;
2196 } 2403 }
2197//FIXME: still races here with signals, but small window to poll() inside read_key
2198 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) 2404 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;)
2199 /* errno = 0; - read_key does this itself */ 2405 /* errno = 0; - read_key does this itself */
2200 ic = read_key(STDIN_FILENO, read_key_buffer, timeout); 2406 ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
@@ -2484,7 +2690,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2484 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2690 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
2485 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ 2691 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */
2486 ); 2692 );
2693#if !ENABLE_PLATFORM_MINGW32
2487 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { 2694 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) {
2695#else
2696 if (n != 0 || !isatty(0)) {
2697#endif
2488 /* Happens when e.g. stty -echo was run before. 2698 /* Happens when e.g. stty -echo was run before.
2489 * But if ICANON is not set, we don't come here. 2699 * But if ICANON is not set, we don't come here.
2490 * (example: interactive python ^Z-backgrounded, 2700 * (example: interactive python ^Z-backgrounded,
@@ -2494,8 +2704,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2494 fflush_all(); 2704 fflush_all();
2495 if (fgets(command, maxsize, stdin) == NULL) 2705 if (fgets(command, maxsize, stdin) == NULL)
2496 len = -1; /* EOF or error */ 2706 len = -1; /* EOF or error */
2497 else 2707 else {
2498 len = strlen(command); 2708 len = strlen(command);
2709#if ENABLE_PLATFORM_MINGW32
2710 len = remove_cr(command, len);
2711#endif
2712 }
2499 DEINIT_S(); 2713 DEINIT_S();
2500 return len; 2714 return len;
2501 } 2715 }
@@ -2577,6 +2791,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2577 } 2791 }
2578#endif 2792#endif
2579 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2793 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2794#if ENABLE_PLATFORM_MINGW32
2795 /* scroll to cursor position on any keypress */
2796 if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
2797 move_cursor_row(0);
2798#endif
2580 2799
2581#if ENABLE_FEATURE_REVERSE_SEARCH 2800#if ENABLE_FEATURE_REVERSE_SEARCH
2582 again: 2801 again:
@@ -2638,6 +2857,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2638 input_tab(&lastWasTab); 2857 input_tab(&lastWasTab);
2639 break; 2858 break;
2640#endif 2859#endif
2860#if ENABLE_PLATFORM_MINGW32
2861 case CTRL('Z'):
2862 command_ps[command_len] = '\0';
2863 #if ENABLE_UNICODE_SUPPORT
2864 bs_to_slash_u(command_ps);
2865 #else
2866 bs_to_slash(command_ps);
2867 #endif
2868 redraw(cmdedit_y, 0);
2869 break;
2870#endif
2641 case CTRL('K'): 2871 case CTRL('K'):
2642 /* Control-k -- clear to end of line */ 2872 /* Control-k -- clear to end of line */
2643 command_ps[cursor] = BB_NUL; 2873 command_ps[cursor] = BB_NUL;
@@ -2892,6 +3122,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2892 && ic_raw == initial_settings.c_cc[VINTR] 3122 && ic_raw == initial_settings.c_cc[VINTR]
2893 ) { 3123 ) {
2894 /* Ctrl-C (usually) - stop gathering input */ 3124 /* Ctrl-C (usually) - stop gathering input */
3125#if ENABLE_PLATFORM_MINGW32
3126 if (state->flags & IGNORE_CTRL_C)
3127 break;
3128#endif
2895 command_len = 0; 3129 command_len = 0;
2896 break_out = -1; /* "do not append '\n'" */ 3130 break_out = -1; /* "do not append '\n'" */
2897 break; 3131 break;
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index 9b03bb8d0..e0fd486d8 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -49,11 +49,19 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
49 } 49 }
50 50
51 org_mask = cur_mask = (mode_t)-1L; 51 org_mask = cur_mask = (mode_t)-1L;
52#if ENABLE_PLATFORM_MINGW32
53 /* normalise path separators, path is already assumed writable */
54 bs_to_slash(path);
55#endif
52 s = path; 56 s = path;
53 while (1) { 57 while (1) {
54 c = '\0'; 58 c = '\0';
55 59
56 if (flags & FILEUTILS_RECUR) { /* Get the parent */ 60 if (flags & FILEUTILS_RECUR) { /* Get the parent */
61#if ENABLE_PLATFORM_MINGW32
62 if (s == path)
63 s += root_len(path);
64#endif
57 /* Bypass leading non-'/'s and then subsequent '/'s */ 65 /* Bypass leading non-'/'s and then subsequent '/'s */
58 while (*s) { 66 while (*s) {
59 if (*s == '/') { 67 if (*s == '/') {
diff --git a/libbb/messages.c b/libbb/messages.c
index 6914d5701..311eda004 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -5,6 +5,9 @@
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 6 */
7#include "libbb.h" 7#include "libbb.h"
8#if ENABLE_PLATFORM_MINGW32
9# include "BB_VER.h"
10#endif
8 11
9/* allow version to be extended, via CFLAGS */ 12/* allow version to be extended, via CFLAGS */
10#ifndef BB_EXTRA_VERSION 13#ifndef BB_EXTRA_VERSION
@@ -27,7 +30,26 @@ const char bb_msg_standard_output[] ALIGN1 = "standard output";
27 30
28const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 31const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
29 32
33#if !ENABLE_PLATFORM_MINGW32
30const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 34const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
35#else
36/* Some special shell variables are placed in the environment immediately
37 * when they're exported.
38 *
39 * BB_GLOBBING and BB_UMASK are excluded because users shouldn't be
40 * messing with them; BB_FIX_BACKSLASH is excluded because it only
41 * affects particular applets, not the shell itself.
42 *
43 * If you change any of these you should also update the definitions in
44 * include/libbb.h.
45 */
46const char bbvar[] ALIGN1 =
47 "BB_OVERRIDE_APPLETS\0" \
48 "BB_SKIP_ANSI_EMULATION\0" \
49 "BB_TERMINAL_MODE\0" \
50 "BB_SYSTEMROOT\0" \
51 "BB_CRITICAL_ERROR_DIALOGS\0";
52#endif
31const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 53const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
32/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 54/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
33 * but I want to save a few bytes here. Check libbb.h before changing! */ 55 * but I want to save a few bytes here. Check libbb.h before changing! */
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 52abe66f7..906c03964 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -19,7 +19,7 @@
19/* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */ 19/* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */
20 20
21#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \ 21#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
22 || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \ 22 || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 && S_IFBLK != 0030000 ) \
23 || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \ 23 || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
24 || ( S_IFIFO != 0010000 ) 24 || ( S_IFIFO != 0010000 )
25# warning mode type bitflag value assumption(s) violated! falling back to larger version 25# warning mode type bitflag value assumption(s) violated! falling back to larger version
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index 8701b010c..bcd667c7c 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -113,8 +113,17 @@ static int get_line_with_continuation(parser_t *parser)
113 line = parser->line; 113 line = parser->line;
114 for (;;) { 114 for (;;) {
115 parser->lineno++; 115 parser->lineno++;
116#if !ENABLE_PLATFORM_MINGW32
116 if (line[len - 1] == '\n') 117 if (line[len - 1] == '\n')
117 len--; 118 len--;
119#else
120 if (line[len - 1] == '\n') {
121 len--;
122 if (len != 0 && line[len - 1] == '\r') {
123 len--;
124 }
125 }
126#endif
118 if (len == 0 || line[len - 1] != '\\') 127 if (len == 0 || line[len - 1] != '\\')
119 break; 128 break;
120 len--; 129 len--;
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c
index fa1f0d339..32adb8c38 100644
--- a/libbb/perror_msg.c
+++ b/libbb/perror_msg.c
@@ -8,7 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_perror_msg(const char *s, ...) 11void bb_perror_msg(const char *s, ...)
12{ 12{
13 va_list p; 13 va_list p;
14 14
@@ -18,7 +18,7 @@ void FAST_FUNC bb_perror_msg(const char *s, ...)
18 va_end(p); 18 va_end(p);
19} 19}
20 20
21void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) 21void bb_perror_msg_and_die(const char *s, ...)
22{ 22{
23 va_list p; 23 va_list p;
24 24
diff --git a/libbb/poll_with_signals.c b/libbb/poll_with_signals.c
new file mode 100644
index 000000000..d3c005418
--- /dev/null
+++ b/libbb/poll_with_signals.c
@@ -0,0 +1,48 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2025 Denys Vlasenko <vda.linux@googlemail.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//kbuild:lib-$(CONFIG_PLATFORM_POSIX) += poll_with_signals.o
10
11#include "libbb.h"
12
13/* Shells, for example, need their line input and "read" builtin
14 * to be interruptible, and the naive handling of it a-la:
15 * if (bb_got_signal) {
16 * errno = EINTR;
17 * return -1;
18 * }
19 * poll(pfd, 1, -1); // signal here would set EINTR
20 * is racy.
21 * This is a bit heavy-handed, but safe wrt races:
22 */
23int FAST_FUNC check_got_signal_and_poll(struct pollfd pfd[1], int timeout)
24{
25 int n;
26 struct timespec tv;
27 sigset_t orig_mask;
28
29 if (bb_got_signal) /* optimization */
30 goto eintr;
31
32 if (timeout >= 0) {
33 tv.tv_sec = timeout / 1000;
34 tv.tv_nsec = (timeout % 1000) * 1000000;
35 }
36 /* test bb_got_signal, then poll(), atomically wrt signals */
37 sigfillset(&orig_mask);
38 sigprocmask2(SIG_BLOCK, &orig_mask);
39 if (bb_got_signal) {
40 sigprocmask2(SIG_SETMASK, &orig_mask);
41 eintr:
42 errno = EINTR; /* inform the caller that we got a signal */
43 return -1;
44 }
45 n = ppoll(pfd, 1, timeout >= 0 ? &tv : NULL, &orig_mask);
46 sigprocmask2(SIG_SETMASK, &orig_mask);
47 return n;
48}
diff --git a/libbb/printable_string.c b/libbb/printable_string.c
index a814fd03c..2e8895a4f 100644
--- a/libbb/printable_string.c
+++ b/libbb/printable_string.c
@@ -42,7 +42,7 @@ const char* FAST_FUNC printable_string2(uni_stat_t *stats, const char *str)
42 unsigned char c = *d; 42 unsigned char c = *d;
43 if (c == '\0') 43 if (c == '\0')
44 break; 44 break;
45 if (c < ' ' || c >= 0x7f) 45 if (c < ' ' || (c >= 0x7f && !ENABLE_PLATFORM_MINGW32))
46 *d = '?'; 46 *d = '?';
47 d++; 47 d++;
48 } 48 }
diff --git a/libbb/procps.c b/libbb/procps.c
index f56b71b21..8c9cac125 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -63,6 +63,7 @@ const char* FAST_FUNC get_cached_groupname(gid_t gid)
63 return get_cached(1, gid, gid2group_utoa); 63 return get_cached(1, gid, gid2group_utoa);
64} 64}
65 65
66#if !ENABLE_PLATFORM_MINGW32
66 67
67#define PROCPS_BUFSIZE 1024 68#define PROCPS_BUFSIZE 1024
68 69
@@ -618,6 +619,8 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
618 } 619 }
619} 620}
620 621
622#endif /* ENABLE_PLATFORM_MINGW32 */
623
621/* from kernel: 624/* from kernel:
622 // pid comm S ppid pgid sid tty_nr tty_pgrp flg 625 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
623 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ 626 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
diff --git a/libbb/pw_ascii64.c b/libbb/pw_ascii64.c
new file mode 100644
index 000000000..3993932ca
--- /dev/null
+++ b/libbb/pw_ascii64.c
@@ -0,0 +1,91 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* Returns >=64 for invalid chars */
11int FAST_FUNC a2i64(char c)
12{
13 unsigned char ch = c;
14 if (ch >= 'a')
15 /* "a..z" to 38..63 */
16 /* anything after "z": positive int >= 64 */
17 return (ch - 'a' + 38);
18
19 if (ch > 'Z')
20 /* after "Z" but before "a": positive byte >= 64 */
21 return ch;
22
23 if (ch >= 'A')
24 /* "A..Z" to 12..37 */
25 return (ch - 'A' + 12);
26
27 if (ch > '9')
28 return 64;
29
30 /* "./0123456789" to 0,1,2..11 */
31 /* anything before "." becomes positive byte >= 64 */
32 return (unsigned char)(ch - '.');
33}
34
35/* 0..63 ->
36 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
37 */
38int FAST_FUNC i2a64(int i)
39{
40 i &= 0x3f;
41
42 i += '.';
43 /* the above maps 0..11 to "./0123456789":
44 * ACSII codes of "./" are ('0'-2) and ('0'-1) */
45
46 if (i > '9')
47 i += ('A' - '9' - 1);
48 if (i > 'Z')
49 i += ('a' - 'Z' - 1);
50 return i;
51}
52
53char* FAST_FUNC
54num2str64_lsb_first(char *s, unsigned v, int n)
55{
56 while (--n >= 0) {
57 *s++ = i2a64(v);
58 v >>= 6;
59 }
60 return s;
61}
62
63static void
64num2str64_4chars_msb_first(char *s, unsigned v)
65{
66 *s++ = i2a64(v >> 18); /* bits 23..18 */
67 *s++ = i2a64(v >> 12); /* bits 17..12 */
68 *s++ = i2a64(v >> 6); /* bits 11..6 */
69 *s = i2a64(v); /* bits 5..0 */
70}
71
72int FAST_FUNC crypt_make_rand64encoded(char *p, int cnt /*, int x */)
73{
74 /* was: x += ... */
75 unsigned x = getpid() + monotonic_us();
76 do {
77 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
78 * (low-order bit is not "random", etc...),
79 * but for our purposes it is good enough */
80 x = x*1664525 + 1013904223;
81 /* BTW, Park and Miller's "minimal standard generator" is
82 * x = x*16807 % ((2^31)-1)
83 * It has no problem with visibly alternating lowest bit
84 * but is also weak in cryptographic sense + needs div,
85 * which needs more code (and slower) on many CPUs */
86 *p++ = i2a64(x >> 16);
87 *p++ = i2a64(x >> 22);
88 } while (--cnt);
89 *p = '\0';
90 return x;
91}
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 3463fd95b..93653de9f 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -13,48 +13,11 @@
13#endif 13#endif
14#include "libbb.h" 14#include "libbb.h"
15 15
16/* static const uint8_t ascii64[] ALIGN1 = 16#include "pw_ascii64.c"
17 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
18 */
19
20static int i64c(int i)
21{
22 i &= 0x3f;
23 if (i == 0)
24 return '.';
25 if (i == 1)
26 return '/';
27 if (i < 12)
28 return ('0' - 2 + i);
29 if (i < 38)
30 return ('A' - 12 + i);
31 return ('a' - 38 + i);
32}
33
34int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */)
35{
36 /* was: x += ... */
37 unsigned x = getpid() + monotonic_us();
38 do {
39 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
40 * (low-order bit is not "random", etc...),
41 * but for our purposes it is good enough */
42 x = x*1664525 + 1013904223;
43 /* BTW, Park and Miller's "minimal standard generator" is
44 * x = x*16807 % ((2^31)-1)
45 * It has no problem with visibly alternating lowest bit
46 * but is also weak in cryptographic sense + needs div,
47 * which needs more code (and slower) on many CPUs */
48 *p++ = i64c(x >> 16);
49 *p++ = i64c(x >> 22);
50 } while (--cnt);
51 *p = '\0';
52 return x;
53}
54 17
55char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) 18char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
56{ 19{
57 int len = 2/2; 20 int len = 2 / 2;
58 char *salt_ptr = salt; 21 char *salt_ptr = salt;
59 22
60 /* Standard chpasswd uses uppercase algos ("MD5", not "md5"). 23 /* Standard chpasswd uses uppercase algos ("MD5", not "md5").
@@ -67,28 +30,61 @@ char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
67 *salt_ptr++ = '$'; 30 *salt_ptr++ = '$';
68#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA 31#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
69 if ((algo[0]|0x20) == 's') { /* sha */ 32 if ((algo[0]|0x20) == 's') { /* sha */
70 salt[1] = '5' + (strcasecmp(algo, "sha512") == 0); 33 salt[1] = '5' + (strncasecmp(algo, "sha512", 6) == 0);
71 len = 16/2; 34 len = 16 / 2;
35 }
36#endif
37#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_YES
38 if ((algo[0]|0x20) == 'y') { /* yescrypt */
39 int rnd;
40 salt[1] = 'y';
41// The "j9T$" below is the default "yescrypt parameters" encoded by yescrypt_encode_params_r():
42//shadow-4.17.4/src/passwd.c
43// salt = crypt_make_salt(NULL, NULL);
44//shadow-4.17.4/lib/salt.c
45//const char *crypt_make_salt(const char *meth, void *arg)
46// if (streq(method, "YESCRYPT")) {
47// MAGNUM(result, 'y');
48// salt_len = YESCRYPT_SALT_SIZE; // 24
49// rounds = YESCRYPT_get_salt_cost(arg); // always Y_COST_DEFAULT == 5 for NULL arg
50// YESCRYPT_salt_cost_to_buf(result, rounds); // always "j9T$"
51// char *retval = crypt_gensalt(result, rounds, NULL, 0);
52//libxcrypt-4.4.38/lib/crypt-yescrypt.c
53//void gensalt_yescrypt_rn (unsigned long count,
54// const uint8_t *rbytes, size_t nrbytes,
55// uint8_t *output, size_t o_size)
56// yescrypt_params_t params = {
57// .flags = YESCRYPT_DEFAULTS,
58// .p = 1,
59// };
60// if (count < 3) ... else
61// params.r = 32; // N in 4KiB
62// params.N = 1ULL << (count + 7); // 3 -> 1024, 4 -> 2048, ... 11 -> 262144
63// yescrypt_encode_params_r(&params, rbytes, nrbytes, outbuf, o_size) // always "$y$j9T$<random>"
64 len = 22 / 2;
65 salt_ptr = stpcpy(salt_ptr, "j9T$");
66 /* append 2*len random chars */
67 rnd = crypt_make_rand64encoded(salt_ptr, len);
68 /* fix up last char: it must be in 0..3 range (encoded as one of "./01").
69 * IOW: salt_ptr[20..21] encode 16th random byte, must not be > 0xff.
70 * Without this, we can generate salts which are rejected
71 * by implementations with more strict salt length check.
72 */
73 salt_ptr[21] = i2a64(rnd & 3);
74 /* For "mkpasswd -m yescrypt PASS j9T$<salt>" use case,
75 * "j9T$" is considered part of salt,
76 * need to return pointer to 'j'. Without -4,
77 * we'd end up using "j9T$j9T$<salt>" as salt.
78 */
79 return salt_ptr - 4;
72 } 80 }
73#endif 81#endif
74 } 82 }
75 crypt_make_salt(salt_ptr, len); 83 crypt_make_rand64encoded(salt_ptr, len); /* appends 2*len random chars */
76 return salt_ptr; 84 return salt_ptr;
77} 85}
78 86
79#if ENABLE_USE_BB_CRYPT 87#if ENABLE_USE_BB_CRYPT
80
81static char*
82to64(char *s, unsigned v, int n)
83{
84 while (--n >= 0) {
85 /* *s++ = ascii64[v & 0x3f]; */
86 *s++ = i64c(v);
87 v >>= 6;
88 }
89 return s;
90}
91
92/* 88/*
93 * DES and MD5 crypt implementations are taken from uclibc. 89 * DES and MD5 crypt implementations are taken from uclibc.
94 * They were modified to not use static buffers. 90 * They were modified to not use static buffers.
@@ -99,6 +95,9 @@ to64(char *s, unsigned v, int n)
99#if ENABLE_USE_BB_CRYPT_SHA 95#if ENABLE_USE_BB_CRYPT_SHA
100#include "pw_encrypt_sha.c" 96#include "pw_encrypt_sha.c"
101#endif 97#endif
98#if ENABLE_USE_BB_CRYPT_YES
99#include "pw_encrypt_yes.c"
100#endif
102 101
103/* Other advanced crypt ids (TODO?): */ 102/* Other advanced crypt ids (TODO?): */
104/* $2$ or $2a$: Blowfish */ 103/* $2$ or $2a$: Blowfish */
@@ -109,7 +108,7 @@ static struct des_ctx *des_ctx;
109/* my_crypt returns malloc'ed data */ 108/* my_crypt returns malloc'ed data */
110static char *my_crypt(const char *key, const char *salt) 109static char *my_crypt(const char *key, const char *salt)
111{ 110{
112 /* MD5 or SHA? */ 111 /* "$x$...." string? */
113 if (salt[0] == '$' && salt[1] && salt[2] == '$') { 112 if (salt[0] == '$' && salt[1] && salt[2] == '$') {
114 if (salt[1] == '1') 113 if (salt[1] == '1')
115 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); 114 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
@@ -117,6 +116,10 @@ static char *my_crypt(const char *key, const char *salt)
117 if (salt[1] == '5' || salt[1] == '6') 116 if (salt[1] == '5' || salt[1] == '6')
118 return sha_crypt((char*)key, (char*)salt); 117 return sha_crypt((char*)key, (char*)salt);
119#endif 118#endif
119#if ENABLE_USE_BB_CRYPT_YES
120 if (salt[1] == 'y')
121 return yes_crypt(key, salt);
122#endif
120 } 123 }
121 124
122 if (!des_cctx) 125 if (!des_cctx)
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index fe8237cfe..ca8aa9bcc 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -186,39 +186,9 @@ static const uint8_t pbox[32] ALIGN1 = {
186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
187}; 187};
188 188
189static const uint32_t bits32[32] ALIGN4 = {
190 0x80000000, 0x40000000, 0x20000000, 0x10000000,
191 0x08000000, 0x04000000, 0x02000000, 0x01000000,
192 0x00800000, 0x00400000, 0x00200000, 0x00100000,
193 0x00080000, 0x00040000, 0x00020000, 0x00010000,
194 0x00008000, 0x00004000, 0x00002000, 0x00001000,
195 0x00000800, 0x00000400, 0x00000200, 0x00000100,
196 0x00000080, 0x00000040, 0x00000020, 0x00000010,
197 0x00000008, 0x00000004, 0x00000002, 0x00000001
198};
199
200static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 189static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
201 190
202 191
203static int
204ascii_to_bin(char ch)
205{
206 if (ch > 'z')
207 return 0;
208 if (ch >= 'a')
209 return (ch - 'a' + 38);
210 if (ch > 'Z')
211 return 0;
212 if (ch >= 'A')
213 return (ch - 'A' + 12);
214 if (ch > '9')
215 return 0;
216 if (ch >= '.')
217 return (ch - '.');
218 return 0;
219}
220
221
222/* Static stuff that stays resident and doesn't change after 192/* Static stuff that stays resident and doesn't change after
223 * being initialized, and therefore doesn't need to be made 193 * being initialized, and therefore doesn't need to be made
224 * reentrant. */ 194 * reentrant. */
@@ -354,11 +324,18 @@ des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx)
354 int i, j, b, k, inbit, obit; 324 int i, j, b, k, inbit, obit;
355 uint32_t p; 325 uint32_t p;
356 const uint32_t *bits28, *bits24; 326 const uint32_t *bits28, *bits24;
327 uint32_t bits32[32];
357 328
358 if (!ctx) 329 if (!ctx)
359 ctx = xmalloc(sizeof(*ctx)); 330 ctx = xmalloc(sizeof(*ctx));
360 const_ctx = cctx; 331 const_ctx = cctx;
361 332
333 p = 0x80000000U;
334 for (i = 0; p; i++) {
335 bits32[i] = p;
336 p >>= 1;
337 }
338
362#if USE_REPETITIVE_SPEEDUP 339#if USE_REPETITIVE_SPEEDUP
363 old_rawkey0 = old_rawkey1 = 0; 340 old_rawkey0 = old_rawkey1 = 0;
364 old_salt = 0; 341 old_salt = 0;
@@ -694,21 +671,6 @@ do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, u
694 671
695#define DES_OUT_BUFSIZE 21 672#define DES_OUT_BUFSIZE 21
696 673
697static void
698to64_msb_first(char *s, unsigned v)
699{
700#if 0
701 *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */
702 *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */
703 *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */
704 *s = ascii64[v & 0x3f]; /* bits 5..0 */
705#endif
706 *s++ = i64c(v >> 18); /* bits 23..18 */
707 *s++ = i64c(v >> 12); /* bits 17..12 */
708 *s++ = i64c(v >> 6); /* bits 11..6 */
709 *s = i64c(v); /* bits 5..0 */
710}
711
712static char * 674static char *
713NOINLINE 675NOINLINE
714des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], 676des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
@@ -740,44 +702,28 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
740 */ 702 */
741 output[0] = salt_str[0]; 703 output[0] = salt_str[0];
742 output[1] = salt_str[1]; 704 output[1] = salt_str[1];
743 salt = (ascii_to_bin(salt_str[1]) << 6) 705
744 | ascii_to_bin(salt_str[0]); 706 salt = a2i64(salt_str[0]);
707 if (salt >= 64)
708 return NULL; /* bad salt char */
709 salt |= (a2i64(salt_str[1]) << 6);
710 if (salt >= (64 << 6))
711 return NULL; /* bad salt char */
745 setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */ 712 setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */
746 713
747 /* Do it. */ 714 /* Do it. */
748 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); 715 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
749 716
750 /* Now encode the result. */ 717 /* Now encode the result. */
751#if 0
752{
753 uint32_t l = (r0 >> 8);
754 q = (uint8_t *)output + 2;
755 *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */
756 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */
757 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */
758 *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */
759 l = ((r0 << 16) | (r1 >> 16));
760 *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */
761 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */
762 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */
763 *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */
764 l = r1 << 2;
765 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */
766 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */
767 *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */
768 *q = 0;
769}
770#else
771 /* Each call takes low-order 24 bits and stores 4 chars */ 718 /* Each call takes low-order 24 bits and stores 4 chars */
772 /* bits 31..8 of r0 */ 719 /* bits 31..8 of r0 */
773 to64_msb_first(output + 2, (r0 >> 8)); 720 num2str64_4chars_msb_first(output + 2, (r0 >> 8));
774 /* bits 7..0 of r0 and 31..16 of r1 */ 721 /* bits 7..0 of r0 and 31..16 of r1 */
775 to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); 722 num2str64_4chars_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
776 /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */ 723 /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
777 to64_msb_first(output + 10, (r1 << 8)); 724 num2str64_4chars_msb_first(output + 10, (r1 << 8));
778 /* extra zero byte is encoded as '.', fixing it */ 725 /* extra zero byte is encoded as '.', fixing it */
779 output[13] = '\0'; 726 output[13] = '\0';
780#endif
781 727
782 return output; 728 return output;
783} 729}
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c
index 1e52ecaea..92d039f96 100644
--- a/libbb/pw_encrypt_md5.c
+++ b/libbb/pw_encrypt_md5.c
@@ -149,9 +149,9 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
149 final[16] = final[5]; 149 final[16] = final[5];
150 for (i = 0; i < 5; i++) { 150 for (i = 0; i < 5; i++) {
151 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; 151 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
152 p = to64(p, l, 4); 152 p = num2str64_lsb_first(p, l, 4);
153 } 153 }
154 p = to64(p, final[11], 2); 154 p = num2str64_lsb_first(p, final[11], 2);
155 *p = '\0'; 155 *p = '\0';
156 156
157 /* Don't leave anything around in vm they could use. */ 157 /* Don't leave anything around in vm they could use. */
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c
index 5457d7ab6..695a5c07f 100644
--- a/libbb/pw_encrypt_sha.c
+++ b/libbb/pw_encrypt_sha.c
@@ -84,8 +84,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
84 as a scratch space later. */ 84 as a scratch space later. */
85 salt_data = xstrndup(salt_data, salt_len); 85 salt_data = xstrndup(salt_data, salt_len);
86 /* add "salt$" to result */ 86 /* add "salt$" to result */
87 strcpy(resptr, salt_data); 87 resptr = stpcpy(resptr, salt_data);
88 resptr += salt_len;
89 *resptr++ = '$'; 88 *resptr++ = '$';
90 /* key data doesn't need much processing */ 89 /* key data doesn't need much processing */
91 key_len = strlen(key_data); 90 key_len = strlen(key_data);
@@ -198,7 +197,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
198#define b64_from_24bit(B2, B1, B0, N) \ 197#define b64_from_24bit(B2, B1, B0, N) \
199do { \ 198do { \
200 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ 199 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
201 resptr = to64(resptr, w, N); \ 200 resptr = num2str64_lsb_first(resptr, w, N); \
202} while (0) 201} while (0)
203 if (_32or64 == 32) { /* sha256 */ 202 if (_32or64 == 32) { /* sha256 */
204 unsigned i = 0; 203 unsigned i = 0;
diff --git a/libbb/pw_encrypt_yes.c b/libbb/pw_encrypt_yes.c
new file mode 100644
index 000000000..50bd06418
--- /dev/null
+++ b/libbb/pw_encrypt_yes.c
@@ -0,0 +1,24 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8#include "yescrypt/alg-yescrypt.h"
9
10static char *
11yes_crypt(const char *passwd, const char *salt_data)
12{
13 /* prefix, '$', hash, NUL */
14 char buf[YESCRYPT_PREFIX_LEN + 1 + YESCRYPT_HASH_LEN + 1];
15 char *retval;
16
17 retval = yescrypt_r(
18 (const uint8_t *)passwd, strlen(passwd),
19 (const uint8_t *)salt_data,
20 buf, sizeof(buf));
21 /* The returned value is either buf[], or NULL on error */
22
23 return xstrdup(retval);
24}
diff --git a/libbb/read_key.c b/libbb/read_key.c
index cf8ed411e..2414105ee 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -11,7 +11,7 @@
11 11
12int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) 12int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
13{ 13{
14 struct pollfd pfd; 14 struct pollfd pfd[1];
15 const char *seq; 15 const char *seq;
16 int n; 16 int n;
17 17
@@ -112,8 +112,13 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
112 0 112 0
113 }; 113 };
114 114
115 pfd.fd = fd; 115#if ENABLE_PLATFORM_MINGW32
116 pfd.events = POLLIN; 116 if (!(terminal_mode(FALSE) & VT_INPUT))
117 return windows_read_key(fd, buffer, timeout);
118#endif
119
120 pfd->fd = fd;
121 pfd->events = POLLIN;
117 122
118 buffer++; /* saved chars counter is in buffer[-1] now */ 123 buffer++; /* saved chars counter is in buffer[-1] now */
119 124
@@ -121,12 +126,16 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
121 errno = 0; 126 errno = 0;
122 n = (unsigned char)buffer[-1]; 127 n = (unsigned char)buffer[-1];
123 if (n == 0) { 128 if (n == 0) {
124 /* If no data, wait for input. 129 /* No data. Wait for input. */
125 * If requested, wait TIMEOUT ms. TIMEOUT = -1 is useful 130
126 * if fd can be in non-blocking mode. 131 /* timeout == -2 means "do not poll". Else: */
127 */
128 if (timeout >= -1) { 132 if (timeout >= -1) {
129 n = poll(&pfd, 1, timeout); 133 /* We must poll even if timeout == -1:
134 * we want to be interrupted if signal arrives,
135 * regardless of SA_RESTART-ness of that signal!
136 */
137 /* test bb_got_signal, then poll(), atomically wrt signals */
138 n = check_got_signal_and_poll(pfd, timeout);
130 if (n < 0 && errno == EINTR) 139 if (n < 0 && errno == EINTR)
131 return n; 140 return n;
132 if (n == 0) { 141 if (n == 0) {
@@ -135,6 +144,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
135 return -1; 144 return -1;
136 } 145 }
137 } 146 }
147
138 /* It is tempting to read more than one byte here, 148 /* It is tempting to read more than one byte here,
139 * but it breaks pasting. Example: at shell prompt, 149 * but it breaks pasting. Example: at shell prompt,
140 * user presses "c","a","t" and then pastes "\nline\n". 150 * user presses "c","a","t" and then pastes "\nline\n".
@@ -173,7 +183,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
173 * so if we block for long it's not really an escape sequence. 183 * so if we block for long it's not really an escape sequence.
174 * Timeout is needed to reconnect escape sequences 184 * Timeout is needed to reconnect escape sequences
175 * split up by transmission over a serial console. */ 185 * split up by transmission over a serial console. */
176 if (safe_poll(&pfd, 1, 50) == 0) { 186 if (safe_poll(pfd, 1, 50) == 0) {
177 /* No more data! 187 /* No more data!
178 * Array is sorted from shortest to longest, 188 * Array is sorted from shortest to longest,
179 * we can't match anything later in array - 189 * we can't match anything later in array -
@@ -222,7 +232,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
222 * n = bytes read. Try to read more until we time out. 232 * n = bytes read. Try to read more until we time out.
223 */ 233 */
224 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ 234 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
225 if (safe_poll(&pfd, 1, 50) == 0) { 235 if (safe_poll(pfd, 1, 50) == 0) {
226 /* No more data! */ 236 /* No more data! */
227 break; 237 break;
228 } 238 }
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 0cd04ab7b..379dd2448 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -93,6 +93,11 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
93 break; 93 break;
94 p++; 94 p++;
95 } 95 }
96#if ENABLE_PLATFORM_MINGW32
97 if ( p != buf && *(p-1) == '\r' ) {
98 --p;
99 }
100#endif
96 *p = '\0'; 101 *p = '\0';
97 if (maxsz_p) 102 if (maxsz_p)
98 *maxsz_p = p - buf; 103 *maxsz_p = p - buf;
diff --git a/libbb/signals.c b/libbb/signals.c
index 0bebc847d..c09a562ed 100644
--- a/libbb/signals.c
+++ b/libbb/signals.c
@@ -18,6 +18,7 @@ void record_signo(int signo)
18 bb_got_signal = signo; 18 bb_got_signal = signo;
19} 19}
20 20
21#if !ENABLE_PLATFORM_MINGW32
21/* Saves 2 bytes on x86! Oh my... */ 22/* Saves 2 bytes on x86! Oh my... */
22int FAST_FUNC sigaction_set(int signum, const struct sigaction *act) 23int FAST_FUNC sigaction_set(int signum, const struct sigaction *act)
23{ 24{
@@ -40,6 +41,7 @@ int FAST_FUNC sigprocmask2(int how, sigset_t *set)
40 oset = set; 41 oset = set;
41 return sigprocmask(how, set, oset); 42 return sigprocmask(how, set, oset);
42} 43}
44#endif
43 45
44void FAST_FUNC bb_signals(int sigs, void (*f)(int)) 46void FAST_FUNC bb_signals(int sigs, void (*f)(int))
45{ 47{
diff --git a/libbb/time.c b/libbb/time.c
index f09ef5d52..e7c9fa65e 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -44,12 +44,21 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
44 save = *ptm; 44 save = *ptm;
45 fmt = fmt_str; 45 fmt = fmt_str;
46 while (*fmt) { 46 while (*fmt) {
47#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_TIMEZONE
48 long gmtoff;
49 endp = mingw_strptime(date_str, fmt, ptm, &gmtoff);
50#else
47 endp = strptime(date_str, fmt, ptm); 51 endp = strptime(date_str, fmt, ptm);
52#endif
48 if (endp && *endp == '\0') { 53 if (endp && *endp == '\0') {
49# if ENABLE_FEATURE_TIMEZONE 54# if ENABLE_FEATURE_TIMEZONE
50 if (strchr(fmt, 'z')) { 55 if (strchr(fmt, 'z')) {
51 /* we have timezone offset: obtain Unix time_t */ 56 /* we have timezone offset: obtain Unix time_t */
57#if ENABLE_PLATFORM_MINGW32
58 ptm->tm_sec -= gmtoff;
59#else
52 ptm->tm_sec -= ptm->tm_gmtoff; 60 ptm->tm_sec -= ptm->tm_gmtoff;
61#endif
53 ptm->tm_isdst = 0; 62 ptm->tm_isdst = 0;
54 t = timegm(ptm); 63 t = timegm(ptm);
55 if (t == (time_t)-1) 64 if (t == (time_t)-1)
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
index f7d598c7a..e233849c5 100644
--- a/libbb/u_signal_names.c
+++ b/libbb/u_signal_names.c
@@ -27,10 +27,19 @@
27 27
28#include "libbb.h" 28#include "libbb.h"
29 29
30#if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM)
31# define SIGLEN 7
32#elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \
33 !ENABLE_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS && defined(__SIGRTMIN))
34# define SIGLEN 6
35#else
36# define SIGLEN 5
37#endif
38
30/* Believe it or not, but some arches have more than 32 SIGs! 39/* Believe it or not, but some arches have more than 32 SIGs!
31 * HPPA: SIGSTKFLT == 36. */ 40 * HPPA: SIGSTKFLT == 36. */
32 41
33static const char signals[][7] ALIGN1 = { 42static const char signals[][SIGLEN] ALIGN1 = {
34 // SUSv3 says kill must support these, and specifies the numerical values, 43 // SUSv3 says kill must support these, and specifies the numerical values,
35 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html 44 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
36 // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"}, 45 // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"},
diff --git a/libbb/unicode.c b/libbb/unicode.c
index e98cbbf35..acc7cd8df 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -69,8 +69,14 @@ void FAST_FUNC init_unicode(void)
69void FAST_FUNC reinit_unicode(const char *LANG) 69void FAST_FUNC reinit_unicode(const char *LANG)
70{ 70{
71 unicode_status = UNICODE_OFF; 71 unicode_status = UNICODE_OFF;
72#if ENABLE_PLATFORM_MINGW32
73 /* enable unicode only when ACP is UTF8 and the env var is not 'C' */
74 if (GetACP() != CP_UTF8 || (LANG && LANG[0] == 'C' && LANG[1] == 0))
75 return;
76#else
72 if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF"))) 77 if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF")))
73 return; 78 return;
79#endif
74 unicode_status = UNICODE_ON; 80 unicode_status = UNICODE_ON;
75} 81}
76 82
@@ -270,7 +276,9 @@ int FAST_FUNC iswpunct(wint_t wc)
270 return (unsigned)wc <= 0x7f && ispunct(wc); 276 return (unsigned)wc <= 0x7f && ispunct(wc);
271} 277}
272 278
279#define WCWIDTH_ALT (ENABLE_PLATFORM_MINGW32 && CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000)
273 280
281# if !WCWIDTH_ALT || ENABLE_UNICODE_BIDI_SUPPORT
274# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 282# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
275struct interval { 283struct interval {
276 uint16_t first; 284 uint16_t first;
@@ -327,7 +335,9 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
327 return 0; 335 return 0;
328} 336}
329# endif 337# endif
338# endif /* !WCWIDTH_ALT || ENABLE_UNICODE_BIDI_SUPPORT */
330 339
340# if !WCWIDTH_ALT
331 341
332/* 342/*
333 * This is an implementation of wcwidth() and wcswidth() (defined in 343 * This is an implementation of wcwidth() and wcswidth() (defined in
@@ -697,6 +707,9 @@ int FAST_FUNC wcwidth(unsigned ucs)
697# endif /* >= 0x300 */ 707# endif /* >= 0x300 */
698} 708}
699 709
710# else /* WCWIDTH_ALT */
711# include "wcwidth_alt.c" /* simpler and more up-to-date implementation */
712# endif
700 713
701# if ENABLE_UNICODE_BIDI_SUPPORT 714# if ENABLE_UNICODE_BIDI_SUPPORT
702int FAST_FUNC unicode_bidi_isrtl(wint_t wc) 715int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
index 74b608f4c..7c167d912 100644
--- a/libbb/verror_msg.c
+++ b/libbb/verror_msg.c
@@ -156,7 +156,7 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
156#endif 156#endif
157 157
158 158
159void FAST_FUNC bb_error_msg_and_die(const char *s, ...) 159void bb_error_msg_and_die(const char *s, ...)
160{ 160{
161 va_list p; 161 va_list p;
162 162
@@ -166,7 +166,7 @@ void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
166 xfunc_die(); 166 xfunc_die();
167} 167}
168 168
169void FAST_FUNC bb_error_msg(const char *s, ...) 169void bb_error_msg(const char *s, ...)
170{ 170{
171 va_list p; 171 va_list p;
172 172
@@ -183,7 +183,7 @@ void FAST_FUNC bb_vinfo_msg(const char *s, va_list p)
183 syslog_level = LOG_ERR; 183 syslog_level = LOG_ERR;
184} 184}
185 185
186void FAST_FUNC bb_info_msg(const char *s, ...) 186void bb_info_msg(const char *s, ...)
187{ 187{
188 va_list p; 188 va_list p;
189 189
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 2055c4b71..dad50ddb9 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -171,6 +171,7 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
171 * Higher-level code, hiding optional NOFORK/NOEXEC trickery. 171 * Higher-level code, hiding optional NOFORK/NOEXEC trickery.
172 */ 172 */
173 173
174#if !ENABLE_PLATFORM_MINGW32
174/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 175/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
175 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 176 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
176pid_t FAST_FUNC spawn(char **argv) 177pid_t FAST_FUNC spawn(char **argv)
@@ -212,6 +213,7 @@ pid_t FAST_FUNC spawn(char **argv)
212 } 213 }
213 return pid; 214 return pid;
214} 215}
216#endif
215 217
216/* Die with an error message if we can't spawn a child process. */ 218/* Die with an error message if we can't spawn a child process. */
217pid_t FAST_FUNC xspawn(char **argv) 219pid_t FAST_FUNC xspawn(char **argv)
@@ -232,6 +234,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
232 if (APPLET_IS_NOFORK(a)) 234 if (APPLET_IS_NOFORK(a))
233 return run_nofork_applet(a, argv); 235 return run_nofork_applet(a, argv);
234# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */ 236# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */
237# if !ENABLE_PLATFORM_MINGW32 /* and then only if not on Microsoft Windows */
235 if (APPLET_IS_NOEXEC(a)) { 238 if (APPLET_IS_NOEXEC(a)) {
236 fflush_all(); 239 fflush_all();
237 rc = fork(); 240 rc = fork();
@@ -241,6 +244,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
241 /* child */ 244 /* child */
242 run_noexec_applet_and_exit(a, argv[0], argv); 245 run_noexec_applet_and_exit(a, argv[0], argv);
243 } 246 }
247# endif
244# endif 248# endif
245 } 249 }
246#endif 250#endif
@@ -248,6 +252,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
248 return wait4pid(rc); 252 return wait4pid(rc);
249} 253}
250 254
255#if !ENABLE_PLATFORM_MINGW32
251#if !BB_MMU 256#if !BB_MMU
252void FAST_FUNC re_exec(char **argv) 257void FAST_FUNC re_exec(char **argv)
253{ 258{
@@ -340,3 +345,4 @@ void FAST_FUNC bb_sanitize_stdio(void)
340{ 345{
341 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL); 346 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
342} 347}
348#endif /* !MINGW32 */
diff --git a/libbb/wcwidth_alt.c b/libbb/wcwidth_alt.c
new file mode 100644
index 000000000..9a45ab0e9
--- /dev/null
+++ b/libbb/wcwidth_alt.c
@@ -0,0 +1,506 @@
1/* wcwidth - Unicode 15.1.0, generated by scripts/mkwcwidth.
2 * Copyright (C) 2024 Avi Halachmi <avihpit at yahoo.com>
3 * License: MIT
4 *
5 * Data imported on 2024-03-29 from https://github.com/jquast/wcwidth
6 * commit 0.2.13-3-g056ee4b (2024-02-14 15:05:06 -0500)
7 */
8int FAST_FUNC wcwidth(uint32_t ucs)
9{
10 /* sorted ranges, "first" is clipped to 16 bit, and its high bits
11 * (plane) are deduced from the "planes" array below.
12 * (imported from table_zero.py and table_wide.py)
13 */
14 static const struct range {
15 uint16_t first;
16 uint16_t iswide: 1; /* bitfield order empirically faster */
17 uint16_t difflast: 15;
18 } ranges[] = {
19 #define R(first, last, width) {first & 0xffff, width/2, last-first}
20 R(0x000000, 0x000000, 0), /* nil */
21 R(0x0000ad, 0x0000ad, 0), /* Soft Hyphen */
22 R(0x000300, 0x00036f, 0), /* Combining Grave Accent ..Combining Latin Small Le */
23 R(0x000483, 0x000489, 0), /* Combining Cyrillic Titlo..Combining Cyrillic Milli */
24 R(0x000591, 0x0005bd, 0), /* Hebrew Accent Etnahta ..Hebrew Point Meteg */
25 R(0x0005bf, 0x0005bf, 0), /* Hebrew Point Rafe */
26 R(0x0005c1, 0x0005c2, 0), /* Hebrew Point Shin Dot ..Hebrew Point Sin Dot */
27 R(0x0005c4, 0x0005c5, 0), /* Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot */
28 R(0x0005c7, 0x0005c7, 0), /* Hebrew Point Qamats Qatan */
29 R(0x000600, 0x000605, 0), /* Arabic Number Sign ..Arabic Number Mark Above */
30 R(0x000610, 0x00061a, 0), /* Arabic Sign Sallallahou ..Arabic Small Kasra */
31 R(0x00061c, 0x00061c, 0), /* Arabic Letter Mark */
32 R(0x00064b, 0x00065f, 0), /* Arabic Fathatan ..Arabic Wavy Hamza Below */
33 R(0x000670, 0x000670, 0), /* Arabic Letter Superscript Alef */
34 R(0x0006d6, 0x0006dd, 0), /* Arabic Small High Ligatu..Arabic End Of Ayah */
35 R(0x0006df, 0x0006e4, 0), /* Arabic Small High Rounde..Arabic Small High Madda */
36 R(0x0006e7, 0x0006e8, 0), /* Arabic Small High Yeh ..Arabic Small High Noon */
37 R(0x0006ea, 0x0006ed, 0), /* Arabic Empty Centre Low ..Arabic Small Low Meem */
38 R(0x00070f, 0x00070f, 0), /* Syriac Abbreviation Mark */
39 R(0x000711, 0x000711, 0), /* Syriac Letter Superscript Alaph */
40 R(0x000730, 0x00074a, 0), /* Syriac Pthaha Above ..Syriac Barrekh */
41 R(0x0007a6, 0x0007b0, 0), /* Thaana Abafili ..Thaana Sukun */
42 R(0x0007eb, 0x0007f3, 0), /* Nko Combining Short High..Nko Combining Double Dot */
43 R(0x0007fd, 0x0007fd, 0), /* Nko Dantayalan */
44 R(0x000816, 0x000819, 0), /* Samaritan Mark In ..Samaritan Mark Dagesh */
45 R(0x00081b, 0x000823, 0), /* Samaritan Mark Epentheti..Samaritan Vowel Sign A */
46 R(0x000825, 0x000827, 0), /* Samaritan Vowel Sign Sho..Samaritan Vowel Sign U */
47 R(0x000829, 0x00082d, 0), /* Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa */
48 R(0x000859, 0x00085b, 0), /* Mandaic Affrication Mark..Mandaic Gemination Mark */
49 R(0x000890, 0x000891, 0), /* Arabic Pound Mark Above ..Arabic Piastre Mark Abov */
50 R(0x000898, 0x00089f, 0), /* Arabic Small High Word A..Arabic Half Madda Over M */
51 R(0x0008ca, 0x000903, 0), /* Arabic Small High Farsi ..Devanagari Sign Visarga */
52 R(0x00093a, 0x00093c, 0), /* Devanagari Vowel Sign Oe..Devanagari Sign Nukta */
53 R(0x00093e, 0x00094f, 0), /* Devanagari Vowel Sign Aa..Devanagari Vowel Sign Aw */
54 R(0x000951, 0x000957, 0), /* Devanagari Stress Sign U..Devanagari Vowel Sign Uu */
55 R(0x000962, 0x000963, 0), /* Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo */
56 R(0x000981, 0x000983, 0), /* Bengali Sign Candrabindu..Bengali Sign Visarga */
57 R(0x0009bc, 0x0009bc, 0), /* Bengali Sign Nukta */
58 R(0x0009be, 0x0009c4, 0), /* Bengali Vowel Sign Aa ..Bengali Vowel Sign Vocal */
59 R(0x0009c7, 0x0009c8, 0), /* Bengali Vowel Sign E ..Bengali Vowel Sign Ai */
60 R(0x0009cb, 0x0009cd, 0), /* Bengali Vowel Sign O ..Bengali Sign Virama */
61 R(0x0009d7, 0x0009d7, 0), /* Bengali Au Length Mark */
62 R(0x0009e2, 0x0009e3, 0), /* Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal */
63 R(0x0009fe, 0x0009fe, 0), /* Bengali Sandhi Mark */
64 R(0x000a01, 0x000a03, 0), /* Gurmukhi Sign Adak Bindi..Gurmukhi Sign Visarga */
65 R(0x000a3c, 0x000a3c, 0), /* Gurmukhi Sign Nukta */
66 R(0x000a3e, 0x000a42, 0), /* Gurmukhi Vowel Sign Aa ..Gurmukhi Vowel Sign Uu */
67 R(0x000a47, 0x000a48, 0), /* Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai */
68 R(0x000a4b, 0x000a4d, 0), /* Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama */
69 R(0x000a51, 0x000a51, 0), /* Gurmukhi Sign Udaat */
70 R(0x000a70, 0x000a71, 0), /* Gurmukhi Tippi ..Gurmukhi Addak */
71 R(0x000a75, 0x000a75, 0), /* Gurmukhi Sign Yakash */
72 R(0x000a81, 0x000a83, 0), /* Gujarati Sign Candrabind..Gujarati Sign Visarga */
73 R(0x000abc, 0x000abc, 0), /* Gujarati Sign Nukta */
74 R(0x000abe, 0x000ac5, 0), /* Gujarati Vowel Sign Aa ..Gujarati Vowel Sign Cand */
75 R(0x000ac7, 0x000ac9, 0), /* Gujarati Vowel Sign E ..Gujarati Vowel Sign Cand */
76 R(0x000acb, 0x000acd, 0), /* Gujarati Vowel Sign O ..Gujarati Sign Virama */
77 R(0x000ae2, 0x000ae3, 0), /* Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca */
78 R(0x000afa, 0x000aff, 0), /* Gujarati Sign Sukun ..Gujarati Sign Two-circle */
79 R(0x000b01, 0x000b03, 0), /* Oriya Sign Candrabindu ..Oriya Sign Visarga */
80 R(0x000b3c, 0x000b3c, 0), /* Oriya Sign Nukta */
81 R(0x000b3e, 0x000b44, 0), /* Oriya Vowel Sign Aa ..Oriya Vowel Sign Vocalic */
82 R(0x000b47, 0x000b48, 0), /* Oriya Vowel Sign E ..Oriya Vowel Sign Ai */
83 R(0x000b4b, 0x000b4d, 0), /* Oriya Vowel Sign O ..Oriya Sign Virama */
84 R(0x000b55, 0x000b57, 0), /* Oriya Sign Overline ..Oriya Au Length Mark */
85 R(0x000b62, 0x000b63, 0), /* Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic */
86 R(0x000b82, 0x000b82, 0), /* Tamil Sign Anusvara */
87 R(0x000bbe, 0x000bc2, 0), /* Tamil Vowel Sign Aa ..Tamil Vowel Sign Uu */
88 R(0x000bc6, 0x000bc8, 0), /* Tamil Vowel Sign E ..Tamil Vowel Sign Ai */
89 R(0x000bca, 0x000bcd, 0), /* Tamil Vowel Sign O ..Tamil Sign Virama */
90 R(0x000bd7, 0x000bd7, 0), /* Tamil Au Length Mark */
91 R(0x000c00, 0x000c04, 0), /* Telugu Sign Combining Ca..Telugu Sign Combining An */
92 R(0x000c3c, 0x000c3c, 0), /* Telugu Sign Nukta */
93 R(0x000c3e, 0x000c44, 0), /* Telugu Vowel Sign Aa ..Telugu Vowel Sign Vocali */
94 R(0x000c46, 0x000c48, 0), /* Telugu Vowel Sign E ..Telugu Vowel Sign Ai */
95 R(0x000c4a, 0x000c4d, 0), /* Telugu Vowel Sign O ..Telugu Sign Virama */
96 R(0x000c55, 0x000c56, 0), /* Telugu Length Mark ..Telugu Ai Length Mark */
97 R(0x000c62, 0x000c63, 0), /* Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali */
98 R(0x000c81, 0x000c83, 0), /* Kannada Sign Candrabindu..Kannada Sign Visarga */
99 R(0x000cbc, 0x000cbc, 0), /* Kannada Sign Nukta */
100 R(0x000cbe, 0x000cc4, 0), /* Kannada Vowel Sign Aa ..Kannada Vowel Sign Vocal */
101 R(0x000cc6, 0x000cc8, 0), /* Kannada Vowel Sign E ..Kannada Vowel Sign Ai */
102 R(0x000cca, 0x000ccd, 0), /* Kannada Vowel Sign O ..Kannada Sign Virama */
103 R(0x000cd5, 0x000cd6, 0), /* Kannada Length Mark ..Kannada Ai Length Mark */
104 R(0x000ce2, 0x000ce3, 0), /* Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal */
105 R(0x000cf3, 0x000cf3, 0), /* Kannada Sign Combining Anusvara Above Right */
106 R(0x000d00, 0x000d03, 0), /* Malayalam Sign Combining..Malayalam Sign Visarga */
107 R(0x000d3b, 0x000d3c, 0), /* Malayalam Sign Vertical ..Malayalam Sign Circular */
108 R(0x000d3e, 0x000d44, 0), /* Malayalam Vowel Sign Aa ..Malayalam Vowel Sign Voc */
109 R(0x000d46, 0x000d48, 0), /* Malayalam Vowel Sign E ..Malayalam Vowel Sign Ai */
110 R(0x000d4a, 0x000d4d, 0), /* Malayalam Vowel Sign O ..Malayalam Sign Virama */
111 R(0x000d57, 0x000d57, 0), /* Malayalam Au Length Mark */
112 R(0x000d62, 0x000d63, 0), /* Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc */
113 R(0x000d81, 0x000d83, 0), /* Sinhala Sign Candrabindu..Sinhala Sign Visargaya */
114 R(0x000dca, 0x000dca, 0), /* Sinhala Sign Al-lakuna */
115 R(0x000dcf, 0x000dd4, 0), /* Sinhala Vowel Sign Aela-..Sinhala Vowel Sign Ketti */
116 R(0x000dd6, 0x000dd6, 0), /* Sinhala Vowel Sign Diga Paa-pilla */
117 R(0x000dd8, 0x000ddf, 0), /* Sinhala Vowel Sign Gaett..Sinhala Vowel Sign Gayan */
118 R(0x000df2, 0x000df3, 0), /* Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga */
119 R(0x000e31, 0x000e31, 0), /* Thai Character Mai Han-akat */
120 R(0x000e34, 0x000e3a, 0), /* Thai Character Sara I ..Thai Character Phinthu */
121 R(0x000e47, 0x000e4e, 0), /* Thai Character Maitaikhu..Thai Character Yamakkan */
122 R(0x000eb1, 0x000eb1, 0), /* Lao Vowel Sign Mai Kan */
123 R(0x000eb4, 0x000ebc, 0), /* Lao Vowel Sign I ..Lao Semivowel Sign Lo */
124 R(0x000ec8, 0x000ece, 0), /* Lao Tone Mai Ek ..Lao Yamakkan */
125 R(0x000f18, 0x000f19, 0), /* Tibetan Astrological Sig..Tibetan Astrological Sig */
126 R(0x000f35, 0x000f35, 0), /* Tibetan Mark Ngas Bzung Nyi Zla */
127 R(0x000f37, 0x000f37, 0), /* Tibetan Mark Ngas Bzung Sgor Rtags */
128 R(0x000f39, 0x000f39, 0), /* Tibetan Mark Tsa -phru */
129 R(0x000f3e, 0x000f3f, 0), /* Tibetan Sign Yar Tshes ..Tibetan Sign Mar Tshes */
130 R(0x000f71, 0x000f84, 0), /* Tibetan Vowel Sign Aa ..Tibetan Mark Halanta */
131 R(0x000f86, 0x000f87, 0), /* Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags */
132 R(0x000f8d, 0x000f97, 0), /* Tibetan Subjoined Sign L..Tibetan Subjoined Letter */
133 R(0x000f99, 0x000fbc, 0), /* Tibetan Subjoined Letter..Tibetan Subjoined Letter */
134 R(0x000fc6, 0x000fc6, 0), /* Tibetan Symbol Padma Gdan */
135 R(0x00102b, 0x00103e, 0), /* Myanmar Vowel Sign Tall ..Myanmar Consonant Sign M */
136 R(0x001056, 0x001059, 0), /* Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal */
137 R(0x00105e, 0x001060, 0), /* Myanmar Consonant Sign M..Myanmar Consonant Sign M */
138 R(0x001062, 0x001064, 0), /* Myanmar Vowel Sign Sgaw ..Myanmar Tone Mark Sgaw K */
139 R(0x001067, 0x00106d, 0), /* Myanmar Vowel Sign Weste..Myanmar Sign Western Pwo */
140 R(0x001071, 0x001074, 0), /* Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah */
141 R(0x001082, 0x00108d, 0), /* Myanmar Consonant Sign S..Myanmar Sign Shan Counci */
142 R(0x00108f, 0x00108f, 0), /* Myanmar Sign Rumai Palaung Tone-5 */
143 R(0x00109a, 0x00109d, 0), /* Myanmar Sign Khamti Tone..Myanmar Vowel Sign Aiton */
144 R(0x001100, 0x00115f, 2), /* Hangul Choseong Kiyeok ..Hangul Choseong Filler */
145 R(0x001160, 0x0011ff, 0), /* Hangul Jungseong Filler ..Hangul Jongseong Ssangni */
146 R(0x00135d, 0x00135f, 0), /* Ethiopic Combining Gemin..Ethiopic Combining Gemin */
147 R(0x001712, 0x001715, 0), /* Tagalog Vowel Sign I ..Tagalog Sign Pamudpod */
148 R(0x001732, 0x001734, 0), /* Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod */
149 R(0x001752, 0x001753, 0), /* Buhid Vowel Sign I ..Buhid Vowel Sign U */
150 R(0x001772, 0x001773, 0), /* Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U */
151 R(0x0017b4, 0x0017d3, 0), /* Khmer Vowel Inherent Aq ..Khmer Sign Bathamasat */
152 R(0x0017dd, 0x0017dd, 0), /* Khmer Sign Atthacan */
153 R(0x00180b, 0x00180f, 0), /* Mongolian Free Variation..Mongolian Free Variation */
154 R(0x001885, 0x001886, 0), /* Mongolian Letter Ali Gal..Mongolian Letter Ali Gal */
155 R(0x0018a9, 0x0018a9, 0), /* Mongolian Letter Ali Gali Dagalga */
156 R(0x001920, 0x00192b, 0), /* Limbu Vowel Sign A ..Limbu Subjoined Letter W */
157 R(0x001930, 0x00193b, 0), /* Limbu Small Letter Ka ..Limbu Sign Sa-i */
158 R(0x001a17, 0x001a1b, 0), /* Buginese Vowel Sign I ..Buginese Vowel Sign Ae */
159 R(0x001a55, 0x001a5e, 0), /* Tai Tham Consonant Sign ..Tai Tham Consonant Sign */
160 R(0x001a60, 0x001a7c, 0), /* Tai Tham Sign Sakot ..Tai Tham Sign Khuen-lue */
161 R(0x001a7f, 0x001a7f, 0), /* Tai Tham Combining Cryptogrammic Dot */
162 R(0x001ab0, 0x001ace, 0), /* Combining Doubled Circum..Combining Latin Small Le */
163 R(0x001b00, 0x001b04, 0), /* Balinese Sign Ulu Ricem ..Balinese Sign Bisah */
164 R(0x001b34, 0x001b44, 0), /* Balinese Sign Rerekan ..Balinese Adeg Adeg */
165 R(0x001b6b, 0x001b73, 0), /* Balinese Musical Symbol ..Balinese Musical Symbol */
166 R(0x001b80, 0x001b82, 0), /* Sundanese Sign Panyecek ..Sundanese Sign Pangwisad */
167 R(0x001ba1, 0x001bad, 0), /* Sundanese Consonant Sign..Sundanese Consonant Sign */
168 R(0x001be6, 0x001bf3, 0), /* Batak Sign Tompi ..Batak Panongonan */
169 R(0x001c24, 0x001c37, 0), /* Lepcha Subjoined Letter ..Lepcha Sign Nukta */
170 R(0x001cd0, 0x001cd2, 0), /* Vedic Tone Karshana ..Vedic Tone Prenkha */
171 R(0x001cd4, 0x001ce8, 0), /* Vedic Sign Yajurvedic Mi..Vedic Sign Visarga Anuda */
172 R(0x001ced, 0x001ced, 0), /* Vedic Sign Tiryak */
173 R(0x001cf4, 0x001cf4, 0), /* Vedic Tone Candra Above */
174 R(0x001cf7, 0x001cf9, 0), /* Vedic Sign Atikrama ..Vedic Tone Double Ring A */
175 R(0x001dc0, 0x001dff, 0), /* Combining Dotted Grave A..Combining Right Arrowhea */
176 R(0x00200b, 0x00200f, 0), /* Zero Width Space ..Right-to-left Mark */
177 R(0x002028, 0x00202e, 0), /* Line Separator ..Right-to-left Override */
178 R(0x002060, 0x002064, 0), /* Word Joiner ..Invisible Plus */
179 R(0x002066, 0x00206f, 0), /* Left-to-right Isolate ..Nominal Digit Shapes */
180 R(0x0020d0, 0x0020f0, 0), /* Combining Left Harpoon A..Combining Asterisk Above */
181 R(0x00231a, 0x00231b, 2), /* Watch ..Hourglass */
182 R(0x002329, 0x00232a, 2), /* Left-pointing Angle Brac..Right-pointing Angle Bra */
183 R(0x0023e9, 0x0023ec, 2), /* Black Right-pointing Dou..Black Down-pointing Doub */
184 R(0x0023f0, 0x0023f0, 2), /* Alarm Clock */
185 R(0x0023f3, 0x0023f3, 2), /* Hourglass With Flowing Sand */
186 R(0x0025fd, 0x0025fe, 2), /* White Medium Small Squar..Black Medium Small Squar */
187 R(0x002614, 0x002615, 2), /* Umbrella With Rain Drops..Hot Beverage */
188 R(0x002648, 0x002653, 2), /* Aries ..Pisces */
189 R(0x00267f, 0x00267f, 2), /* Wheelchair Symbol */
190 R(0x002693, 0x002693, 2), /* Anchor */
191 R(0x0026a1, 0x0026a1, 2), /* High Voltage Sign */
192 R(0x0026aa, 0x0026ab, 2), /* Medium White Circle ..Medium Black Circle */
193 R(0x0026bd, 0x0026be, 2), /* Soccer Ball ..Baseball */
194 R(0x0026c4, 0x0026c5, 2), /* Snowman Without Snow ..Sun Behind Cloud */
195 R(0x0026ce, 0x0026ce, 2), /* Ophiuchus */
196 R(0x0026d4, 0x0026d4, 2), /* No Entry */
197 R(0x0026ea, 0x0026ea, 2), /* Church */
198 R(0x0026f2, 0x0026f3, 2), /* Fountain ..Flag In Hole */
199 R(0x0026f5, 0x0026f5, 2), /* Sailboat */
200 R(0x0026fa, 0x0026fa, 2), /* Tent */
201 R(0x0026fd, 0x0026fd, 2), /* Fuel Pump */
202 R(0x002705, 0x002705, 2), /* White Heavy Check Mark */
203 R(0x00270a, 0x00270b, 2), /* Raised Fist ..Raised Hand */
204 R(0x002728, 0x002728, 2), /* Sparkles */
205 R(0x00274c, 0x00274c, 2), /* Cross Mark */
206 R(0x00274e, 0x00274e, 2), /* Negative Squared Cross Mark */
207 R(0x002753, 0x002755, 2), /* Black Question Mark Orna..White Exclamation Mark O */
208 R(0x002757, 0x002757, 2), /* Heavy Exclamation Mark Symbol */
209 R(0x002795, 0x002797, 2), /* Heavy Plus Sign ..Heavy Division Sign */
210 R(0x0027b0, 0x0027b0, 2), /* Curly Loop */
211 R(0x0027bf, 0x0027bf, 2), /* Double Curly Loop */
212 R(0x002b1b, 0x002b1c, 2), /* Black Large Square ..White Large Square */
213 R(0x002b50, 0x002b50, 2), /* White Medium Star */
214 R(0x002b55, 0x002b55, 2), /* Heavy Large Circle */
215 R(0x002cef, 0x002cf1, 0), /* Coptic Combining Ni Abov..Coptic Combining Spiritu */
216 R(0x002d7f, 0x002d7f, 0), /* Tifinagh Consonant Joiner */
217 R(0x002de0, 0x002dff, 0), /* Combining Cyrillic Lette..Combining Cyrillic Lette */
218 R(0x002e80, 0x002e99, 2), /* Cjk Radical Repeat ..Cjk Radical Rap */
219 R(0x002e9b, 0x002ef3, 2), /* Cjk Radical Choke ..Cjk Radical C-simplified */
220 R(0x002f00, 0x002fd5, 2), /* Kangxi Radical One ..Kangxi Radical Flute */
221 R(0x002ff0, 0x003029, 2), /* Ideographic Description ..Hangzhou Numeral Nine */
222 R(0x00302a, 0x00302f, 0), /* Ideographic Level Tone M..Hangul Double Dot Tone M */
223 R(0x003030, 0x00303e, 2), /* Wavy Dash ..Ideographic Variation In */
224 R(0x003041, 0x003096, 2), /* Hiragana Letter Small A ..Hiragana Letter Small Ke */
225 R(0x003099, 0x00309a, 0), /* Combining Katakana-hirag..Combining Katakana-hirag */
226 R(0x00309b, 0x0030ff, 2), /* Katakana-hiragana Voiced..Katakana Digraph Koto */
227 R(0x003105, 0x00312f, 2), /* Bopomofo Letter B ..Bopomofo Letter Nn */
228 R(0x003131, 0x00318e, 2), /* Hangul Letter Kiyeok ..Hangul Letter Araeae */
229 R(0x003190, 0x0031e3, 2), /* Ideographic Annotation L..Cjk Stroke Q */
230 R(0x0031ef, 0x00321e, 2), /* nil ..Parenthesized Korean Cha */
231 R(0x003220, 0x003247, 2), /* Parenthesized Ideograph ..Circled Ideograph Koto */
232 R(0x003250, 0x004dbf, 2), /* Partnership Sign ..Cjk Unified Ideograph-4d */
233 R(0x004e00, 0x00a48c, 2), /* Cjk Unified Ideograph-4e..Yi Syllable Yyr */
234 R(0x00a490, 0x00a4c6, 2), /* Yi Radical Qot ..Yi Radical Ke */
235 R(0x00a66f, 0x00a672, 0), /* Combining Cyrillic Vzmet..Combining Cyrillic Thous */
236 R(0x00a674, 0x00a67d, 0), /* Combining Cyrillic Lette..Combining Cyrillic Payer */
237 R(0x00a69e, 0x00a69f, 0), /* Combining Cyrillic Lette..Combining Cyrillic Lette */
238 R(0x00a6f0, 0x00a6f1, 0), /* Bamum Combining Mark Koq..Bamum Combining Mark Tuk */
239 R(0x00a802, 0x00a802, 0), /* Syloti Nagri Sign Dvisvara */
240 R(0x00a806, 0x00a806, 0), /* Syloti Nagri Sign Hasanta */
241 R(0x00a80b, 0x00a80b, 0), /* Syloti Nagri Sign Anusvara */
242 R(0x00a823, 0x00a827, 0), /* Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign */
243 R(0x00a82c, 0x00a82c, 0), /* Syloti Nagri Sign Alternate Hasanta */
244 R(0x00a880, 0x00a881, 0), /* Saurashtra Sign Anusvara..Saurashtra Sign Visarga */
245 R(0x00a8b4, 0x00a8c5, 0), /* Saurashtra Consonant Sig..Saurashtra Sign Candrabi */
246 R(0x00a8e0, 0x00a8f1, 0), /* Combining Devanagari Dig..Combining Devanagari Sig */
247 R(0x00a8ff, 0x00a8ff, 0), /* Devanagari Vowel Sign Ay */
248 R(0x00a926, 0x00a92d, 0), /* Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop */
249 R(0x00a947, 0x00a953, 0), /* Rejang Vowel Sign I ..Rejang Virama */
250 R(0x00a960, 0x00a97c, 2), /* Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo */
251 R(0x00a980, 0x00a983, 0), /* Javanese Sign Panyangga ..Javanese Sign Wignyan */
252 R(0x00a9b3, 0x00a9c0, 0), /* Javanese Sign Cecak Telu..Javanese Pangkon */
253 R(0x00a9e5, 0x00a9e5, 0), /* Myanmar Sign Shan Saw */
254 R(0x00aa29, 0x00aa36, 0), /* Cham Vowel Sign Aa ..Cham Consonant Sign Wa */
255 R(0x00aa43, 0x00aa43, 0), /* Cham Consonant Sign Final Ng */
256 R(0x00aa4c, 0x00aa4d, 0), /* Cham Consonant Sign Fina..Cham Consonant Sign Fina */
257 R(0x00aa7b, 0x00aa7d, 0), /* Myanmar Sign Pao Karen T..Myanmar Sign Tai Laing T */
258 R(0x00aab0, 0x00aab0, 0), /* Tai Viet Mai Kang */
259 R(0x00aab2, 0x00aab4, 0), /* Tai Viet Vowel I ..Tai Viet Vowel U */
260 R(0x00aab7, 0x00aab8, 0), /* Tai Viet Mai Khit ..Tai Viet Vowel Ia */
261 R(0x00aabe, 0x00aabf, 0), /* Tai Viet Vowel Am ..Tai Viet Tone Mai Ek */
262 R(0x00aac1, 0x00aac1, 0), /* Tai Viet Tone Mai Tho */
263 R(0x00aaeb, 0x00aaef, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign */
264 R(0x00aaf5, 0x00aaf6, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Virama */
265 R(0x00abe3, 0x00abea, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign */
266 R(0x00abec, 0x00abed, 0), /* Meetei Mayek Lum Iyek ..Meetei Mayek Apun Iyek */
267 R(0x00ac00, 0x00d7a3, 2), /* Hangul Syllable Ga ..Hangul Syllable Hih */
268 R(0x00d7b0, 0x00d7ff, 0), /* Hangul Jungseong O-yeo .. nil */
269 R(0x00f900, 0x00faff, 2), /* Cjk Compatibility Ideogr.. nil */
270 R(0x00fb1e, 0x00fb1e, 0), /* Hebrew Point Judeo-spanish Varika */
271 R(0x00fe00, 0x00fe0f, 0), /* Variation Selector-1 ..Variation Selector-16 */
272 R(0x00fe10, 0x00fe19, 2), /* Presentation Form For Ve..Presentation Form For Ve */
273 R(0x00fe20, 0x00fe2f, 0), /* Combining Ligature Left ..Combining Cyrillic Titlo */
274 R(0x00fe30, 0x00fe52, 2), /* Presentation Form For Ve..Small Full Stop */
275 R(0x00fe54, 0x00fe66, 2), /* Small Semicolon ..Small Equals Sign */
276 R(0x00fe68, 0x00fe6b, 2), /* Small Reverse Solidus ..Small Commercial At */
277 R(0x00feff, 0x00feff, 0), /* Zero Width No-break Space */
278 R(0x00ff01, 0x00ff60, 2), /* Fullwidth Exclamation Ma..Fullwidth Right White Pa */
279 R(0x00ffe0, 0x00ffe6, 2), /* Fullwidth Cent Sign ..Fullwidth Won Sign */
280 R(0x00fff9, 0x00fffb, 0), /* Interlinear Annotation A..Interlinear Annotation T */
281 R(0x0101fd, 0x0101fd, 0), /* Phaistos Disc Sign Combining Oblique Stroke */
282 R(0x0102e0, 0x0102e0, 0), /* Coptic Epact Thousands Mark */
283 R(0x010376, 0x01037a, 0), /* Combining Old Permic Let..Combining Old Permic Let */
284 R(0x010a01, 0x010a03, 0), /* Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo */
285 R(0x010a05, 0x010a06, 0), /* Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O */
286 R(0x010a0c, 0x010a0f, 0), /* Kharoshthi Vowel Length ..Kharoshthi Sign Visarga */
287 R(0x010a38, 0x010a3a, 0), /* Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo */
288 R(0x010a3f, 0x010a3f, 0), /* Kharoshthi Virama */
289 R(0x010ae5, 0x010ae6, 0), /* Manichaean Abbreviation ..Manichaean Abbreviation */
290 R(0x010d24, 0x010d27, 0), /* Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas */
291 R(0x010eab, 0x010eac, 0), /* Yezidi Combining Hamza M..Yezidi Combining Madda M */
292 R(0x010efd, 0x010eff, 0), /* Arabic Small Low Word Sa..Arabic Small Low Word Ma */
293 R(0x010f46, 0x010f50, 0), /* Sogdian Combining Dot Be..Sogdian Combining Stroke */
294 R(0x010f82, 0x010f85, 0), /* Old Uyghur Combining Dot..Old Uyghur Combining Two */
295 R(0x011000, 0x011002, 0), /* Brahmi Sign Candrabindu ..Brahmi Sign Visarga */
296 R(0x011038, 0x011046, 0), /* Brahmi Vowel Sign Aa ..Brahmi Virama */
297 R(0x011070, 0x011070, 0), /* Brahmi Sign Old Tamil Virama */
298 R(0x011073, 0x011074, 0), /* Brahmi Vowel Sign Old Ta..Brahmi Vowel Sign Old Ta */
299 R(0x01107f, 0x011082, 0), /* Brahmi Number Joiner ..Kaithi Sign Visarga */
300 R(0x0110b0, 0x0110ba, 0), /* Kaithi Vowel Sign Aa ..Kaithi Sign Nukta */
301 R(0x0110bd, 0x0110bd, 0), /* Kaithi Number Sign */
302 R(0x0110c2, 0x0110c2, 0), /* Kaithi Vowel Sign Vocalic R */
303 R(0x0110cd, 0x0110cd, 0), /* Kaithi Number Sign Above */
304 R(0x011100, 0x011102, 0), /* Chakma Sign Candrabindu ..Chakma Sign Visarga */
305 R(0x011127, 0x011134, 0), /* Chakma Vowel Sign A ..Chakma Maayyaa */
306 R(0x011145, 0x011146, 0), /* Chakma Vowel Sign Aa ..Chakma Vowel Sign Ei */
307 R(0x011173, 0x011173, 0), /* Mahajani Sign Nukta */
308 R(0x011180, 0x011182, 0), /* Sharada Sign Candrabindu..Sharada Sign Visarga */
309 R(0x0111b3, 0x0111c0, 0), /* Sharada Vowel Sign Aa ..Sharada Sign Virama */
310 R(0x0111c9, 0x0111cc, 0), /* Sharada Sandhi Mark ..Sharada Extra Short Vowe */
311 R(0x0111ce, 0x0111cf, 0), /* Sharada Vowel Sign Prish..Sharada Sign Inverted Ca */
312 R(0x01122c, 0x011237, 0), /* Khojki Vowel Sign Aa ..Khojki Sign Shadda */
313 R(0x01123e, 0x01123e, 0), /* Khojki Sign Sukun */
314 R(0x011241, 0x011241, 0), /* Khojki Vowel Sign Vocalic R */
315 R(0x0112df, 0x0112ea, 0), /* Khudawadi Sign Anusvara ..Khudawadi Sign Virama */
316 R(0x011300, 0x011303, 0), /* Grantha Sign Combining A..Grantha Sign Visarga */
317 R(0x01133b, 0x01133c, 0), /* Combining Bindu Below ..Grantha Sign Nukta */
318 R(0x01133e, 0x011344, 0), /* Grantha Vowel Sign Aa ..Grantha Vowel Sign Vocal */
319 R(0x011347, 0x011348, 0), /* Grantha Vowel Sign Ee ..Grantha Vowel Sign Ai */
320 R(0x01134b, 0x01134d, 0), /* Grantha Vowel Sign Oo ..Grantha Sign Virama */
321 R(0x011357, 0x011357, 0), /* Grantha Au Length Mark */
322 R(0x011362, 0x011363, 0), /* Grantha Vowel Sign Vocal..Grantha Vowel Sign Vocal */
323 R(0x011366, 0x01136c, 0), /* Combining Grantha Digit ..Combining Grantha Digit */
324 R(0x011370, 0x011374, 0), /* Combining Grantha Letter..Combining Grantha Letter */
325 R(0x011435, 0x011446, 0), /* Newa Vowel Sign Aa ..Newa Sign Nukta */
326 R(0x01145e, 0x01145e, 0), /* Newa Sandhi Mark */
327 R(0x0114b0, 0x0114c3, 0), /* Tirhuta Vowel Sign Aa ..Tirhuta Sign Nukta */
328 R(0x0115af, 0x0115b5, 0), /* Siddham Vowel Sign Aa ..Siddham Vowel Sign Vocal */
329 R(0x0115b8, 0x0115c0, 0), /* Siddham Vowel Sign E ..Siddham Sign Nukta */
330 R(0x0115dc, 0x0115dd, 0), /* Siddham Vowel Sign Alter..Siddham Vowel Sign Alter */
331 R(0x011630, 0x011640, 0), /* Modi Vowel Sign Aa ..Modi Sign Ardhacandra */
332 R(0x0116ab, 0x0116b7, 0), /* Takri Sign Anusvara ..Takri Sign Nukta */
333 R(0x01171d, 0x01172b, 0), /* Ahom Consonant Sign Medi..Ahom Sign Killer */
334 R(0x01182c, 0x01183a, 0), /* Dogra Vowel Sign Aa ..Dogra Sign Nukta */
335 R(0x011930, 0x011935, 0), /* Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign E */
336 R(0x011937, 0x011938, 0), /* Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign O */
337 R(0x01193b, 0x01193e, 0), /* Dives Akuru Sign Anusvar..Dives Akuru Virama */
338 R(0x011940, 0x011940, 0), /* Dives Akuru Medial Ya */
339 R(0x011942, 0x011943, 0), /* Dives Akuru Medial Ra ..Dives Akuru Sign Nukta */
340 R(0x0119d1, 0x0119d7, 0), /* Nandinagari Vowel Sign A..Nandinagari Vowel Sign V */
341 R(0x0119da, 0x0119e0, 0), /* Nandinagari Vowel Sign E..Nandinagari Sign Virama */
342 R(0x0119e4, 0x0119e4, 0), /* Nandinagari Vowel Sign Prishthamatra E */
343 R(0x011a01, 0x011a0a, 0), /* Zanabazar Square Vowel S..Zanabazar Square Vowel L */
344 R(0x011a33, 0x011a39, 0), /* Zanabazar Square Final C..Zanabazar Square Sign Vi */
345 R(0x011a3b, 0x011a3e, 0), /* Zanabazar Square Cluster..Zanabazar Square Cluster */
346 R(0x011a47, 0x011a47, 0), /* Zanabazar Square Subjoiner */
347 R(0x011a51, 0x011a5b, 0), /* Soyombo Vowel Sign I ..Soyombo Vowel Length Mar */
348 R(0x011a8a, 0x011a99, 0), /* Soyombo Final Consonant ..Soyombo Subjoiner */
349 R(0x011c2f, 0x011c36, 0), /* Bhaiksuki Vowel Sign Aa ..Bhaiksuki Vowel Sign Voc */
350 R(0x011c38, 0x011c3f, 0), /* Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Virama */
351 R(0x011c92, 0x011ca7, 0), /* Marchen Subjoined Letter..Marchen Subjoined Letter */
352 R(0x011ca9, 0x011cb6, 0), /* Marchen Subjoined Letter..Marchen Sign Candrabindu */
353 R(0x011d31, 0x011d36, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign */
354 R(0x011d3a, 0x011d3a, 0), /* Masaram Gondi Vowel Sign E */
355 R(0x011d3c, 0x011d3d, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign */
356 R(0x011d3f, 0x011d45, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Virama */
357 R(0x011d47, 0x011d47, 0), /* Masaram Gondi Ra-kara */
358 R(0x011d8a, 0x011d8e, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign */
359 R(0x011d90, 0x011d91, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign */
360 R(0x011d93, 0x011d97, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Virama */
361 R(0x011ef3, 0x011ef6, 0), /* Makasar Vowel Sign I ..Makasar Vowel Sign O */
362 R(0x011f00, 0x011f01, 0), /* Kawi Sign Candrabindu ..Kawi Sign Anusvara */
363 R(0x011f03, 0x011f03, 0), /* Kawi Sign Visarga */
364 R(0x011f34, 0x011f3a, 0), /* Kawi Vowel Sign Aa ..Kawi Vowel Sign Vocalic */
365 R(0x011f3e, 0x011f42, 0), /* Kawi Vowel Sign E ..Kawi Conjoiner */
366 R(0x013430, 0x013440, 0), /* Egyptian Hieroglyph Vert..Egyptian Hieroglyph Mirr */
367 R(0x013447, 0x013455, 0), /* Egyptian Hieroglyph Modi..Egyptian Hieroglyph Modi */
368 R(0x016af0, 0x016af4, 0), /* Bassa Vah Combining High..Bassa Vah Combining High */
369 R(0x016b30, 0x016b36, 0), /* Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta */
370 R(0x016f4f, 0x016f4f, 0), /* Miao Sign Consonant Modifier Bar */
371 R(0x016f51, 0x016f87, 0), /* Miao Sign Aspiration ..Miao Vowel Sign Ui */
372 R(0x016f8f, 0x016f92, 0), /* Miao Tone Right ..Miao Tone Below */
373 R(0x016fe0, 0x016fe3, 2), /* Tangut Iteration Mark ..Old Chinese Iteration Ma */
374 R(0x016fe4, 0x016fe4, 0), /* Khitan Small Script Filler */
375 R(0x016ff0, 0x016ff1, 0), /* Vietnamese Alternate Rea..Vietnamese Alternate Rea */
376 R(0x017000, 0x0187f7, 2), /* nil */
377 R(0x018800, 0x018cd5, 2), /* Tangut Component-001 ..Khitan Small Script Char */
378 R(0x018d00, 0x018d08, 2), /* nil */
379 R(0x01aff0, 0x01aff3, 2), /* Katakana Letter Minnan T..Katakana Letter Minnan T */
380 R(0x01aff5, 0x01affb, 2), /* Katakana Letter Minnan T..Katakana Letter Minnan N */
381 R(0x01affd, 0x01affe, 2), /* Katakana Letter Minnan N..Katakana Letter Minnan N */
382 R(0x01b000, 0x01b122, 2), /* Katakana Letter Archaic ..Katakana Letter Archaic */
383 R(0x01b132, 0x01b132, 2), /* Hiragana Letter Small Ko */
384 R(0x01b150, 0x01b152, 2), /* Hiragana Letter Small Wi..Hiragana Letter Small Wo */
385 R(0x01b155, 0x01b155, 2), /* Katakana Letter Small Ko */
386 R(0x01b164, 0x01b167, 2), /* Katakana Letter Small Wi..Katakana Letter Small N */
387 R(0x01b170, 0x01b2fb, 2), /* Nushu Character-1b170 ..Nushu Character-1b2fb */
388 R(0x01bc9d, 0x01bc9e, 0), /* Duployan Thick Letter Se..Duployan Double Mark */
389 R(0x01bca0, 0x01bca3, 0), /* Shorthand Format Letter ..Shorthand Format Up Step */
390 R(0x01cf00, 0x01cf2d, 0), /* Znamenny Combining Mark ..Znamenny Combining Mark */
391 R(0x01cf30, 0x01cf46, 0), /* Znamenny Combining Tonal..Znamenny Priznak Modifie */
392 R(0x01d165, 0x01d169, 0), /* Musical Symbol Combining..Musical Symbol Combining */
393 R(0x01d16d, 0x01d182, 0), /* Musical Symbol Combining..Musical Symbol Combining */
394 R(0x01d185, 0x01d18b, 0), /* Musical Symbol Combining..Musical Symbol Combining */
395 R(0x01d1aa, 0x01d1ad, 0), /* Musical Symbol Combining..Musical Symbol Combining */
396 R(0x01d242, 0x01d244, 0), /* Combining Greek Musical ..Combining Greek Musical */
397 R(0x01da00, 0x01da36, 0), /* Signwriting Head Rim ..Signwriting Air Sucking */
398 R(0x01da3b, 0x01da6c, 0), /* Signwriting Mouth Closed..Signwriting Excitement */
399 R(0x01da75, 0x01da75, 0), /* Signwriting Upper Body Tilting From Hip Joints */
400 R(0x01da84, 0x01da84, 0), /* Signwriting Location Head Neck */
401 R(0x01da9b, 0x01da9f, 0), /* Signwriting Fill Modifie..Signwriting Fill Modifie */
402 R(0x01daa1, 0x01daaf, 0), /* Signwriting Rotation Mod..Signwriting Rotation Mod */
403 R(0x01e000, 0x01e006, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
404 R(0x01e008, 0x01e018, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
405 R(0x01e01b, 0x01e021, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
406 R(0x01e023, 0x01e024, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
407 R(0x01e026, 0x01e02a, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
408 R(0x01e08f, 0x01e08f, 0), /* Combining Cyrillic Small Letter Byelorussian-ukr */
409 R(0x01e130, 0x01e136, 0), /* Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T */
410 R(0x01e2ae, 0x01e2ae, 0), /* Toto Sign Rising Tone */
411 R(0x01e2ec, 0x01e2ef, 0), /* Wancho Tone Tup ..Wancho Tone Koini */
412 R(0x01e4ec, 0x01e4ef, 0), /* Nag Mundari Sign Muhor ..Nag Mundari Sign Sutuh */
413 R(0x01e8d0, 0x01e8d6, 0), /* Mende Kikakui Combining ..Mende Kikakui Combining */
414 R(0x01e944, 0x01e94a, 0), /* Adlam Alif Lengthener ..Adlam Nukta */
415 R(0x01f004, 0x01f004, 2), /* Mahjong Tile Red Dragon */
416 R(0x01f0cf, 0x01f0cf, 2), /* Playing Card Black Joker */
417 R(0x01f18e, 0x01f18e, 2), /* Negative Squared Ab */
418 R(0x01f191, 0x01f19a, 2), /* Squared Cl ..Squared Vs */
419 R(0x01f200, 0x01f202, 2), /* Square Hiragana Hoka ..Squared Katakana Sa */
420 R(0x01f210, 0x01f23b, 2), /* Squared Cjk Unified Ideo..Squared Cjk Unified Ideo */
421 R(0x01f240, 0x01f248, 2), /* Tortoise Shell Bracketed..Tortoise Shell Bracketed */
422 R(0x01f250, 0x01f251, 2), /* Circled Ideograph Advant..Circled Ideograph Accept */
423 R(0x01f260, 0x01f265, 2), /* Rounded Symbol For Fu ..Rounded Symbol For Cai */
424 R(0x01f300, 0x01f320, 2), /* Cyclone ..Shooting Star */
425 R(0x01f32d, 0x01f335, 2), /* Hot Dog ..Cactus */
426 R(0x01f337, 0x01f37c, 2), /* Tulip ..Baby Bottle */
427 R(0x01f37e, 0x01f393, 2), /* Bottle With Popping Cork..Graduation Cap */
428 R(0x01f3a0, 0x01f3ca, 2), /* Carousel Horse ..Swimmer */
429 R(0x01f3cf, 0x01f3d3, 2), /* Cricket Bat And Ball ..Table Tennis Paddle And */
430 R(0x01f3e0, 0x01f3f0, 2), /* House Building ..European Castle */
431 R(0x01f3f4, 0x01f3f4, 2), /* Waving Black Flag */
432 R(0x01f3f8, 0x01f3fa, 2), /* Badminton Racquet And Sh..Amphora */
433 R(0x01f3fb, 0x01f3ff, 0), /* Emoji Modifier Fitzpatri..Emoji Modifier Fitzpatri */
434 R(0x01f400, 0x01f43e, 2), /* Rat ..Paw Prints */
435 R(0x01f440, 0x01f440, 2), /* Eyes */
436 R(0x01f442, 0x01f4fc, 2), /* Ear ..Videocassette */
437 R(0x01f4ff, 0x01f53d, 2), /* Prayer Beads ..Down-pointing Small Red */
438 R(0x01f54b, 0x01f54e, 2), /* Kaaba ..Menorah With Nine Branch */
439 R(0x01f550, 0x01f567, 2), /* Clock Face One Oclock ..Clock Face Twelve-thirty */
440 R(0x01f57a, 0x01f57a, 2), /* Man Dancing */
441 R(0x01f595, 0x01f596, 2), /* Reversed Hand With Middl..Raised Hand With Part Be */
442 R(0x01f5a4, 0x01f5a4, 2), /* Black Heart */
443 R(0x01f5fb, 0x01f64f, 2), /* Mount Fuji ..Person With Folded Hands */
444 R(0x01f680, 0x01f6c5, 2), /* Rocket ..Left Luggage */
445 R(0x01f6cc, 0x01f6cc, 2), /* Sleeping Accommodation */
446 R(0x01f6d0, 0x01f6d2, 2), /* Place Of Worship ..Shopping Trolley */
447 R(0x01f6d5, 0x01f6d7, 2), /* Hindu Temple ..Elevator */
448 R(0x01f6dc, 0x01f6df, 2), /* Wireless ..Ring Buoy */
449 R(0x01f6eb, 0x01f6ec, 2), /* Airplane Departure ..Airplane Arriving */
450 R(0x01f6f4, 0x01f6fc, 2), /* Scooter ..Roller Skate */
451 R(0x01f7e0, 0x01f7eb, 2), /* Large Orange Circle ..Large Brown Square */
452 R(0x01f7f0, 0x01f7f0, 2), /* Heavy Equals Sign */
453 R(0x01f90c, 0x01f93a, 2), /* Pinched Fingers ..Fencer */
454 R(0x01f93c, 0x01f945, 2), /* Wrestlers ..Goal Net */
455 R(0x01f947, 0x01f9ff, 2), /* First Place Medal ..Nazar Amulet */
456 R(0x01fa70, 0x01fa7c, 2), /* Ballet Shoes ..Crutch */
457 R(0x01fa80, 0x01fa88, 2), /* Yo-yo ..Flute */
458 R(0x01fa90, 0x01fabd, 2), /* Ringed Planet ..Wing */
459 R(0x01fabf, 0x01fac5, 2), /* Goose ..Person With Crown */
460 R(0x01face, 0x01fadb, 2), /* Moose ..Pea Pod */
461 R(0x01fae0, 0x01fae8, 2), /* Melting Face ..Shaking Face */
462 R(0x01faf0, 0x01faf8, 2), /* Hand With Index Finger A..Rightwards Pushing Hand */
463 R(0x020000, 0x027fff, 2), /* Cjk Unified Ideograph-20.. nil */
464 R(0x028000, 0x02fffd, 2), /* (continued...) */
465 R(0x030000, 0x037fff, 2), /* Cjk Unified Ideograph-30.. nil */
466 R(0x038000, 0x03fffd, 2), /* (continued...) */
467 R(0x0e0001, 0x0e0001, 0), /* Language Tag */
468 R(0x0e0020, 0x0e007f, 0), /* Tag Space ..Cancel Tag */
469 R(0x0e0100, 0x0e01ef, 0), /* Variation Selector-17 ..Variation Selector-256 */
470 #undef R
471 };
472
473 /* planes[p], planes[p+1] are [from, to) at "ranges" for plane p */
474 static const uint16_t planes[/* 18 */] = {
475 0, 261, 443, 445, 447, 447, 447, 447, 447, 447, 447, 447,
476 447, 447, 447, 450, 450, 450,
477 };
478
479 /******* END OF STATIC DATA *******/
480
481 uint32_t p, bot, top;
482
483 /* 0:0, 1..31:-1 (C0), 32..126:1 (isprint), 127..159:-1 (DEL, C1) */
484 if (ucs < 160)
485 return ((ucs + 1) & 127) > 32 ? 1 : ucs ? -1 : 0;
486
487 /* out of range for "planes" (and non-unicode), non-characters. */
488 /* (some also test surrogate halves, but not required by POSIX) */
489 if (ucs > 0x10ffff || (ucs & 0xfffe) == 0xfffe)
490 return -1;
491
492 p = ucs >> 16;
493 ucs &= 0xffff;
494
495 for (bot = planes[p], top = planes[p+1]; bot < top; ) {
496 uint32_t mid = (bot + top) / 2;
497 if (ucs < ranges[mid].first)
498 top = mid;
499 else if (ucs > ranges[mid].first + ranges[mid].difflast)
500 bot = mid + 1;
501 else
502 return 2 * ranges[mid].iswide;
503 }
504
505 return 1;
506} /* wcwidth - Unicode 15.1.0 */
diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c
index e0471983c..0d5d35b47 100644
--- a/libbb/xatonum_template.c
+++ b/libbb/xatonum_template.c
@@ -67,7 +67,7 @@ unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
67 if (r >= lower && r <= upper) 67 if (r >= lower && r <= upper)
68 return r; 68 return r;
69 range: 69 range:
70 bb_error_msg_and_die("number %s is not in %llu..%llu range", 70 bb_error_msg_and_die("number %s is not in %"LL_FMT"u..%"LL_FMT"u range",
71 numstr, (unsigned long long)lower, 71 numstr, (unsigned long long)lower,
72 (unsigned long long)upper); 72 (unsigned long long)upper);
73 inval: 73 inval:
@@ -144,7 +144,8 @@ type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
144 } 144 }
145 145
146 if (r < lower || r > upper) { 146 if (r < lower || r > upper) {
147 bb_error_msg_and_die("number %s is not in %lld..%lld range", 147 bb_error_msg_and_die("number %s is not in "
148 "%"LL_FMT"d..%"LL_FMT"d range",
148 numstr, (long long)lower, (long long)upper); 149 numstr, (long long)lower, (long long)upper);
149 } 150 }
150 151
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 0e0b247b8..65b1cb8de 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -71,6 +71,7 @@ int FAST_FUNC setsockopt_bindtodevice(int fd UNUSED_PARAM,
71} 71}
72#endif 72#endif
73 73
74#if !ENABLE_PLATFORM_MINGW32
74static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen)) 75static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen))
75{ 76{
76 len_and_sockaddr lsa; 77 len_and_sockaddr lsa;
@@ -99,16 +100,17 @@ len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd)
99{ 100{
100 return get_lsa(fd, getpeername); 101 return get_lsa(fd, getpeername);
101} 102}
103#endif
102 104
103void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 105void FAST_FUNC xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen)
104{ 106{
105 if (connect(s, s_addr, addrlen) < 0) { 107 if (connect(s, saddr, addrlen) < 0) {
106 if (ENABLE_FEATURE_CLEAN_UP) 108 if (ENABLE_FEATURE_CLEAN_UP)
107 close(s); 109 close(s);
108 if (s_addr->sa_family == AF_INET) 110 if (saddr->sa_family == AF_INET)
109 bb_perror_msg_and_die("%s (%s)", 111 bb_perror_msg_and_die("%s (%s)",
110 "can't connect to remote host", 112 "can't connect to remote host",
111 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 113 inet_ntoa(((struct sockaddr_in *)saddr)->sin_addr));
112 bb_simple_perror_msg_and_die("can't connect to remote host"); 114 bb_simple_perror_msg_and_die("can't connect to remote host");
113 } 115 }
114} 116}
@@ -348,6 +350,10 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
348#if ENABLE_FEATURE_IPV6 350#if ENABLE_FEATURE_IPV6
349 fd = socket(AF_INET6, sock_type, 0); 351 fd = socket(AF_INET6, sock_type, 0);
350 if (fd >= 0) { 352 if (fd >= 0) {
353#if ENABLE_PLATFORM_MINGW32
354 DWORD buffer = 0;
355 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &buffer, sizeof(DWORD));
356#endif
351 family = AF_INET6; 357 family = AF_INET6;
352 goto done; 358 goto done;
353 } 359 }
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index b03af8542..5609858d1 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -23,6 +23,7 @@
23#include "libbb.h" 23#include "libbb.h"
24 24
25/* Turn on nonblocking I/O on a fd */ 25/* Turn on nonblocking I/O on a fd */
26#if !ENABLE_PLATFORM_MINGW32
26int FAST_FUNC ndelay_on(int fd) 27int FAST_FUNC ndelay_on(int fd)
27{ 28{
28 int flags = fcntl(fd, F_GETFL); 29 int flags = fcntl(fd, F_GETFL);
@@ -45,6 +46,7 @@ void FAST_FUNC close_on_exec_on(int fd)
45{ 46{
46 fcntl(fd, F_SETFD, FD_CLOEXEC); 47 fcntl(fd, F_SETFD, FD_CLOEXEC);
47} 48}
49#endif
48 50
49char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) 51char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
50{ 52{
@@ -219,7 +221,12 @@ off_t FAST_FUNC fdlength(int fd)
219 221
220int FAST_FUNC bb_putchar_stderr(char ch) 222int FAST_FUNC bb_putchar_stderr(char ch)
221{ 223{
224#if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT)
225 // Workaround for problems with stderr in MSVCRT
226 return fputc(ch, stderr);
227#else
222 return write(STDERR_FILENO, &ch, 1); 228 return write(STDERR_FILENO, &ch, 1);
229#endif
223} 230}
224 231
225ssize_t FAST_FUNC full_write1_str(const char *str) 232ssize_t FAST_FUNC full_write1_str(const char *str)
@@ -268,6 +275,7 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh
268 int err; 275 int err;
269 int close_me = -1; 276 int close_me = -1;
270 277
278#if !ENABLE_PLATFORM_MINGW32
271 if (fd == -1) { 279 if (fd == -1) {
272 if (isatty(STDOUT_FILENO)) 280 if (isatty(STDOUT_FILENO))
273 fd = STDOUT_FILENO; 281 fd = STDOUT_FILENO;
@@ -280,6 +288,7 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh
280 else 288 else
281 close_me = fd = open("/dev/tty", O_RDONLY); 289 close_me = fd = open("/dev/tty", O_RDONLY);
282 } 290 }
291#endif
283 292
284 win.ws_row = 0; 293 win.ws_row = 0;
285 win.ws_col = 0; 294 win.ws_col = 0;
@@ -314,7 +323,7 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
314 return tcsetattr(STDIN_FILENO, TCSANOW, tp); 323 return tcsetattr(STDIN_FILENO, TCSANOW, tp);
315} 324}
316 325
317int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags) 326int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags IF_PLATFORM_MINGW32(UNUSED_PARAM))
318{ 327{
319//TODO: slattach, shell read might be adapted to use this too: grep for "tcsetattr", "[VTIME] = 0" 328//TODO: slattach, shell read might be adapted to use this too: grep for "tcsetattr", "[VTIME] = 0"
320 int r; 329 int r;
@@ -323,6 +332,10 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t
323 r = tcgetattr(fd, oldterm); 332 r = tcgetattr(fd, oldterm);
324 *newterm = *oldterm; 333 *newterm = *oldterm;
325 334
335#if ENABLE_PLATFORM_MINGW32
336 newterm->w_mode &=
337 ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
338#else
326 /* Turn off buffered input (ICANON) 339 /* Turn off buffered input (ICANON)
327 * Turn off echoing (ECHO) 340 * Turn off echoing (ECHO)
328 * and separate echoing of newline (ECHONL, normally off anyway) 341 * and separate echoing of newline (ECHONL, normally off anyway)
@@ -379,6 +392,7 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t
379 */ 392 */
380 newterm->c_iflag &= ~(IXOFF|IXON|IXANY|BRKINT|INLCR|ICRNL|IUCLC|IMAXBEL); 393 newterm->c_iflag &= ~(IXOFF|IXON|IXANY|BRKINT|INLCR|ICRNL|IUCLC|IMAXBEL);
381 } 394 }
395#endif
382 return r; 396 return r;
383} 397}
384 398
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 842d10cd2..0ead3b2eb 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -108,6 +108,7 @@ void* FAST_FUNC xmemdup(const void *s, size_t n)
108 return memcpy(xmalloc(n), s, n); 108 return memcpy(xmalloc(n), s, n);
109} 109}
110 110
111#if !ENABLE_PLATFORM_MINGW32
111void* FAST_FUNC mmap_read(int fd, size_t size) 112void* FAST_FUNC mmap_read(int fd, size_t size)
112{ 113{
113 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 114 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -128,6 +129,7 @@ void* FAST_FUNC xmmap_anon(size_t size)
128 bb_die_memory_exhausted(); 129 bb_die_memory_exhausted();
129 return p; 130 return p;
130} 131}
132#endif
131 133
132// Die if we can't open a file and return a FILE* to it. 134// Die if we can't open a file and return a FILE* to it.
133// Notice we haven't got xfread(), This is for use with fscanf() and friends. 135// Notice we haven't got xfread(), This is for use with fscanf() and friends.
@@ -334,7 +336,7 @@ void FAST_FUNC xprint_and_close_file(FILE *file)
334 336
335// Die with an error message if we can't malloc() enough space and do an 337// Die with an error message if we can't malloc() enough space and do an
336// sprintf() into that space. 338// sprintf() into that space.
337char* FAST_FUNC xasprintf(const char *format, ...) 339char* xasprintf(const char *format, ...)
338{ 340{
339 va_list p; 341 va_list p;
340 int r; 342 int r;
@@ -501,6 +503,7 @@ void FAST_FUNC xlisten(int s, int backlog)
501 if (listen(s, backlog)) bb_simple_perror_msg_and_die("listen"); 503 if (listen(s, backlog)) bb_simple_perror_msg_and_die("listen");
502} 504}
503 505
506#if !ENABLE_PLATFORM_MINGW32
504/* Die with an error message if sendto failed. 507/* Die with an error message if sendto failed.
505 * Return bytes sent otherwise */ 508 * Return bytes sent otherwise */
506ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 509ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
@@ -514,6 +517,7 @@ ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct socka
514 } 517 }
515 return ret; 518 return ret;
516} 519}
520#endif
517 521
518// xstat() - a stat() which dies on failure with meaningful error message 522// xstat() - a stat() which dies on failure with meaningful error message
519void FAST_FUNC xstat(const char *name, struct stat *stat_buf) 523void FAST_FUNC xstat(const char *name, struct stat *stat_buf)
@@ -547,7 +551,8 @@ void FAST_FUNC selinux_or_die(void)
547/* not defined, other code must have no calls to it */ 551/* not defined, other code must have no calls to it */
548#endif 552#endif
549 553
550int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) 554#if !ENABLE_PLATFORM_MINGW32
555int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
551{ 556{
552 int ret; 557 int ret;
553 va_list p; 558 va_list p;
@@ -563,7 +568,7 @@ int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, cons
563 return ret; 568 return ret;
564} 569}
565 570
566int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) 571int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
567{ 572{
568 va_list p; 573 va_list p;
569 int ret = ioctl(fd, request, argp); 574 int ret = ioctl(fd, request, argp);
@@ -711,6 +716,7 @@ void FAST_FUNC xvfork_parent_waits_and_exits(void)
711 } 716 }
712 /* Child continues */ 717 /* Child continues */
713} 718}
719#endif /* !ENABLE_PLATFORM_MINGW32 */
714 720
715// Useful when we do know that pid is valid, and we just want to wait 721// Useful when we do know that pid is valid, and we just want to wait
716// for it to exit. Not existing pid is fatal. waitpid() status is not returned. 722// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
@@ -724,11 +730,13 @@ int FAST_FUNC wait_for_exitstatus(pid_t pid)
724 return exit_status; 730 return exit_status;
725} 731}
726 732
733#if !ENABLE_PLATFORM_MINGW32
727void FAST_FUNC xsettimeofday(const struct timeval *tv) 734void FAST_FUNC xsettimeofday(const struct timeval *tv)
728{ 735{
729 if (settimeofday(tv, NULL)) 736 if (settimeofday(tv, NULL))
730 bb_simple_perror_msg_and_die("settimeofday"); 737 bb_simple_perror_msg_and_die("settimeofday");
731} 738}
739#endif
732 740
733void FAST_FUNC xgettimeofday(struct timeval *tv) 741void FAST_FUNC xgettimeofday(struct timeval *tv)
734{ 742{
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index 2682f6975..fc10a2939 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -17,6 +17,7 @@
17 * NOTE: This function returns a malloced char* that you will have to free 17 * NOTE: This function returns a malloced char* that you will have to free
18 * yourself. 18 * yourself.
19 */ 19 */
20#if !ENABLE_PLATFORM_MINGW32
20char* FAST_FUNC xmalloc_readlink(const char *path) 21char* FAST_FUNC xmalloc_readlink(const char *path)
21{ 22{
22 enum { GROWBY = 80 }; /* how large we will grow strings by */ 23 enum { GROWBY = 80 }; /* how large we will grow strings by */
@@ -38,6 +39,7 @@ char* FAST_FUNC xmalloc_readlink(const char *path)
38 39
39 return buf; 40 return buf;
40} 41}
42#endif
41 43
42/* 44/*
43 * This routine is not the same as realpath(), which 45 * This routine is not the same as realpath(), which
@@ -64,19 +66,26 @@ char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
64 linkpath = xmalloc_readlink(buf); 66 linkpath = xmalloc_readlink(buf);
65 if (!linkpath) { 67 if (!linkpath) {
66 /* not a symlink, or doesn't exist */ 68 /* not a symlink, or doesn't exist */
67 if (errno == EINVAL || errno == ENOENT) 69 if (errno == EINVAL || errno == ENOENT || (ENABLE_PLATFORM_MINGW32 && errno == ENOSYS))
68 return buf; 70 return buf;
69 goto free_buf_ret_null; 71 goto free_buf_ret_null;
70 } 72 }
71 73
72 if (!--looping) { 74 if (!--looping) {
75#if ENABLE_PLATFORM_MINGW32
76 errno = ELOOP;
77#endif
73 free(linkpath); 78 free(linkpath);
74 free_buf_ret_null: 79 free_buf_ret_null:
75 free(buf); 80 free(buf);
76 return NULL; 81 return NULL;
77 } 82 }
78 83
84#if ENABLE_PLATFORM_MINGW32
85 if (is_relative_path(linkpath)) {
86#else
79 if (*linkpath != '/') { 87 if (*linkpath != '/') {
88#endif
80 bufsize += strlen(linkpath); 89 bufsize += strlen(linkpath);
81 buf = xrealloc(buf, bufsize); 90 buf = xrealloc(buf, bufsize);
82 lpc = bb_get_last_path_component_strip(buf); 91 lpc = bb_get_last_path_component_strip(buf);
@@ -149,7 +158,11 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
149 * $ realpath symlink 158 * $ realpath symlink
150 * /usr/bin/qwe 159 * /usr/bin/qwe
151 */ 160 */
161#if ENABLE_PLATFORM_MINGW32
162 if (is_relative_path(target)) {
163#else
152 if (target[0] != '/') { 164 if (target[0] != '/') {
165#endif
153 /* 166 /*
154 * $ ln -s target_does_not_exist symlink 167 * $ ln -s target_does_not_exist symlink
155 * $ readlink -f symlink 168 * $ readlink -f symlink
@@ -168,6 +181,35 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
168 return buf; 181 return buf;
169 } 182 }
170 183
184#if ENABLE_PLATFORM_MINGW32
185 /* ignore leading and trailing slashes */
186 /* but keep leading slashes of UNC path */
187 if (!is_unc_path(path)) {
188 while (is_dir_sep(path[0]) && is_dir_sep(path[1]))
189 ++path;
190 }
191 i = strlen(path) - 1;
192 while (i > 0 && is_dir_sep(path[i]))
193 i--;
194 c = path[i + 1];
195 path[i + 1] = '\0';
196
197 last_slash = get_last_slash(path);
198 if (last_slash == path + root_len(path))
199 buf = xstrdup(path);
200 else if (last_slash) {
201 char c2 = *last_slash;
202 *last_slash = '\0';
203 buf = xmalloc_realpath(path);
204 *last_slash++ = c2;
205 if (buf) {
206 unsigned len = strlen(buf);
207 buf = xrealloc(buf, len + strlen(last_slash) + 2);
208 buf[len++] = c2;
209 strcpy(buf + len, last_slash);
210 }
211 }
212#else
171 /* ignore leading and trailing slashes */ 213 /* ignore leading and trailing slashes */
172 while (path[0] == '/' && path[1] == '/') 214 while (path[0] == '/' && path[1] == '/')
173 ++path; 215 ++path;
@@ -191,6 +233,7 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
191 strcpy(buf + len, last_slash); 233 strcpy(buf + len, last_slash);
192 } 234 }
193 } 235 }
236#endif
194 path[i + 1] = c; 237 path[i + 1] = c;
195 } 238 }
196 239
diff --git a/libbb/yescrypt/Kbuild.src b/libbb/yescrypt/Kbuild.src
new file mode 100644
index 000000000..a61211a29
--- /dev/null
+++ b/libbb/yescrypt/Kbuild.src
@@ -0,0 +1,9 @@
1# Makefile for busybox
2#
3# Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
4#
5# Licensed under GPLv2, see file LICENSE in this source tree.
6
7lib-y:=
8
9INSERT
diff --git a/libbb/yescrypt/PARAMETERS b/libbb/yescrypt/PARAMETERS
new file mode 100644
index 000000000..d9f5d24e6
--- /dev/null
+++ b/libbb/yescrypt/PARAMETERS
@@ -0,0 +1,196 @@
1 Optimal yescrypt configuration.
2
3yescrypt is very flexible, but configuring it optimally is complicated.
4Here are some guidelines to simplify near-optimal configuration. We
5start by listing the parameters and their typical values, and then give
6currently recommended parameter sets by use case.
7
8
9 Parameters and their typical values.
10
11Set flags (yescrypt flavor) to YESCRYPT_DEFAULTS to use the currently
12recommended flavor. (Other flags values exist for compatibility and for
13specialized cases where you think you know what you're doing.)
14
15Set N (block count) based on target memory usage and running time, as
16well as on the value of r (block size in 128 byte units). N must be a
17power of two.
18
19Set r (block size) to 8 (so that N is in KiB, which is convenient) or to
20another small value (if more optimal or for fine-tuning of the total
21size and/or running time). Reasonable values for r are from 8 to 96.
22
23Set p (parallelism) to 1 meaning no thread-level parallelism within one
24computation of yescrypt. (Use of thread-level parallelism within
25yescrypt makes sense for ROM initialization and for key derivation at
26high memory usage, but usually not for password hashing where
27parallelism is available through concurrent authentication attempts.
28Don't use p > 1 unnecessarily.)
29
30Set t (time) to 0 to use the optimal running time for a given memory
31usage. This will allow you to maximize the memory usage (the value of
32N*r) while staying within your running time constraints. (Non-zero t
33makes sense in specialized cases where you can't afford higher memory
34usage but can afford more time.)
35
36Set g (upgrades) to 0 because there have been no hash upgrades yet.
37
38Set NROM (block count of ROM) to 0 unless you use a ROM (see below).
39NROM must be a power of two.
40
41
42 Password hashing for user authentication, no ROM.
43
44Small and fast (memory usage 2 MiB, performance like bcrypt cost 2^5 -
45latency 2-3 ms and throughput 10,000+ per second on a 16-core server):
46
47flags = YESCRYPT_DEFAULTS, N = 2048, r = 8, p = 1, t = 0, g = 0, NROM = 0
48
49Large and slow (memory usage 16 MiB, performance like bcrypt cost 2^8 -
50latency 10-30 ms and throughput 1000+ per second on a 16-core server):
51
52flags = YESCRYPT_DEFAULTS, N = 4096, r = 32, p = 1, t = 0, g = 0, NROM = 0
53
54Of course, even heavier and slower settings are possible, if affordable.
55Simply double the value of N as many times as needed. Since N must be a
56power of two, you may use r (in the range of 8 to 32) or/and t (in the
57range of 0 to 2) for fine-tuning the running time, but first bring N to
58the maximum you can afford. If this feels too complicated, just use one
59of the two parameter sets given above (preferably the second) as-is.
60
61
62 Password hashing for user authentication, with ROM.
63
64It's similar to the above, except that you need to adjust r, set NROM,
65and initialize the ROM.
66
67First decide on a ROM size, such as making it a large portion of your
68dedicated authentication servers' RAM sizes. Since NROM (block count)
69must be a power of two, you might need to choose r (block size) based on
70how your desired ROM size corresponds to a power of two. Also tuning
71for performance on current hardware, you'll likely end up with r in the
72range from slightly below 16 to 32. For example, to use 15/16 of a
73server's 256 GiB RAM as ROM (thus, making it 240 GiB), you could use
74r=15 or r=30. To use 23/24 of a server's 384 GiB RAM as ROM (thus,
75making it 368 GiB), you'd use r=23. Then set NROM to your desired ROM
76size in KiB divided by 128*r. Note that these examples might (or might
77not) be too extreme, leaving little memory for the rest of the system.
78You could as well opt for 7/8 with r=14 or 11/12 with r=11 or r=22.
79
80Note that higher r may make placing of ROM in e.g. NVMe flash memory
81instead of in RAM more reasonable (or less unreasonable) than it would
82have been with a lower r. If this is a concern as it relates to
83possible attacks and you do not intend to ever do it defensively, you
84might want to keep r lower (e.g., prefer r=15 over r=30 in the example
85above, even if 30 performs slightly faster).
86
87Your adjustments to r, if you deviate from powers of two, will also
88result in weirder memory usage per hash. Like 1.75 MiB at r=14 instead
89of 2 MiB at r=8 that you would have used without a ROM. That's OK.
90
91For ROM initialization, which you do with yescrypt_init_shared(), use
92the same r and NROM that you'd later use for password hashing, choose p
93based on your servers' physical and/or logical CPU count (maybe
94considering eventual upgrades as you won't be able to change this later,
95but without going unnecessarily high - e.g., p=28, p=56, or p=112 make
96sense on servers that currently have 28 physical / 56 logical CPUs), and
97set the rest of the parameters to:
98
99flags = YESCRYPT_DEFAULTS, N = 0, t = 0, g = 0
100
101N is set to 0 because it isn't relevant during ROM initialization (you
102can use different values of N for hashing passwords with the same ROM).
103
104To keep the ROM in e.g. SysV shared memory and reuse it across your
105authentication service restarts, you'd need to allocate the memory and
106set the flags to "YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED".
107
108For actual password hashing, you'd use your chosen values for N, r,
109NROM, and set the rest of the parameters to:
110
111flags = YESCRYPT_DEFAULTS, p = 1, t = 0, g = 0
112
113Note that although you'd use a large p for ROM initialization, you
114should use p=1 for actual password hashing like you would without a ROM.
115
116Do not forget to pass the ROM into the actual password hashing (and keep
117r and NROM set accordingly).
118
119Since N must be a power of two and r is dependent on ROM size, you may
120use t (in the range of 0 to 2) for fine-tuning the running time, but
121first bring N to the maximum you can afford.
122
123If this feels too complicated, or even if it doesn't, please consider
124engaging Openwall for your yescrypt deployment. We'd be happy to help.
125
126
127 Password-based key derivation.
128
129(Or rather passphrase-based.)
130
131Use settings similar to those for password hashing without a ROM, but
132adjusted for higher memory usage and running time, and optionally with
133thread-level parallelism.
134
135Small and fast (memory usage 128 MiB, running time under 100 ms on a
136fast desktop):
137
138flags = YESCRYPT_DEFAULTS, N = 32768, r = 32, p = 1, t = 0, g = 0, NROM = 0
139
140Large and fast (memory usage 1 GiB, running time under 200 ms on a fast
141quad-core desktop not including memory allocation overhead, under 250 ms
142with the overhead included), but requires build with OpenMP support (or
143otherwise will run as slow as yet be weaker than its p=1 alternative):
144
145flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 0, g = 0, NROM = 0
146
147Large and slower (memory usage 1 GiB, running time under 300 ms on a
148fast quad-core desktop not including memory allocation overhead, under
149350 ms with the overhead included), also requires build with OpenMP
150support (or otherwise will run slower than the p=1 alternative below):
151
152flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 2, g = 0, NROM = 0
153
154Large and slow (memory usage 1 GiB, running time under 600 ms on a fast
155desktop not including memory allocation overhead, under 650 ms with the
156overhead included):
157
158flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 1, t = 0, g = 0, NROM = 0
159
160Just like with password hashing, even heavier and slower settings are
161possible, if affordable, and you achieve them by adjusting N, r, t in
162the same way and in the same preferred ranges (please see the section on
163password hashing without a ROM, above). Unlike with password hashing,
164it makes some sense to go above t=2 if you expect that your users might
165not be able to afford more memory but can afford more time. However,
166increasing the memory usage provides better protection, and we don't
167recommend forcing your users to wait for more than 1 second as they
168could as well type more characters in that time. If this feels too
169complicated, just use one of the above parameter sets as-is.
170
171
172 Amortization of memory allocation overhead.
173
174It takes a significant fraction of yescrypt's total running time to
175allocate memory from the operating system, especially considering that
176the kernel zeroizes the memory before handing it over to your program.
177
178Unless you naturally need to compute yescrypt just once per process, you
179may achieve greater efficiency by fully using advanced yescrypt APIs
180that let you preserve and reuse the memory allocation across yescrypt
181invocations. This is done by reusing the structure pointed to by the
182"yescrypt_local_t *local" argument of yescrypt_r() or yescrypt_kdf()
183without calling yescrypt_free_local() inbetween the repeated invocations
184of yescrypt.
185
186
187 YESCRYPT_DEFAULTS macro.
188
189Please note that the value of the YESCRYPT_DEFAULTS macro might change
190later, so if you use the macro like it's recommended here then for
191results reproducible across versions you might need to store its value
192somewhere along with the hashes or the encrypted data.
193
194If you use yescrypt's standard hash string encoding, then yescrypt
195already encodes and decodes this value for you, so you don't need to
196worry about this.
diff --git a/libbb/yescrypt/README b/libbb/yescrypt/README
new file mode 100644
index 000000000..c1011c56a
--- /dev/null
+++ b/libbb/yescrypt/README
@@ -0,0 +1,4 @@
1The yescrypt code in this directory is adapted from libxcrypt-4.4.38
2with minimal edits, hopefully making it easier to track
3backports by resetting the tree to the commit which created this file,
4then comparing changes in upstream libxcrypt to the tree.
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c
new file mode 100644
index 000000000..20e8d1ee4
--- /dev/null
+++ b/libbb/yescrypt/alg-sha256.c
@@ -0,0 +1,86 @@
1/*-
2 * Copyright 2005-2016 Colin Percival
3 * Copyright 2016-2018,2021 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/**
29 * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
30 * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
31 * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
32 */
33static void
34PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
35 const uint8_t *salt, size_t saltlen,
36 uint64_t c, uint8_t *buf, size_t dkLen)
37{
38 hmac_ctx_t Phctx, PShctx;
39 uint32_t i;
40
41 /* Compute HMAC state after processing P. */
42 hmac_begin(&Phctx, passwd, passwdlen, sha256_begin);
43
44 /* Compute HMAC state after processing P and S. */
45 PShctx = Phctx;
46 hmac_hash(&PShctx, salt, saltlen);
47
48 /* Iterate through the blocks. */
49 for (i = 0; dkLen != 0; ) {
50 uint64_t U[32 / 8];
51 uint64_t T[32 / 8];
52 uint64_t j;
53 uint32_t ivec;
54 size_t clen;
55 int k;
56
57 /* Generate INT(i). */
58 i++;
59 ivec = SWAP_BE32(i);
60
61 /* Compute U_1 = PRF(P, S || INT(i)). */
62 hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL);
63//TODO: the above is a vararg function, might incur some ABI pain
64//does libbb need a non-vararg version with just one (buf,len)?
65
66 if (c > 1) {
67 /* T_i = U_1 ... */
68 memcpy(U, T, 32);
69 for (j = 2; j <= c; j++) {
70 /* Compute U_j. */
71 hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL);
72 /* ... xor U_j ... */
73 for (k = 0; k < 32 / 8; k++)
74 T[k] ^= U[k];
75 //TODO: xorbuf32_aligned_long(T, U);
76 }
77 }
78
79 /* Copy as many bytes as necessary into buf. */
80 clen = dkLen;
81 if (clen > 32)
82 clen = 32;
83 buf = mempcpy(buf, T, clen);
84 dkLen -= clen;
85 }
86}
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c
new file mode 100644
index 000000000..c51823787
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt-common.c
@@ -0,0 +1,408 @@
1/*-
2 * Copyright 2013-2018 Alexander Peslyak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
9 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
12 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18 * SUCH DAMAGE.
19 */
20
21#if RESTRICTED_PARAMS
22
23#define decode64_uint32(dst, src, min) \
24({ \
25 uint32_t d32 = a2i64(*(src)); \
26 if (d32 > 47) \
27 goto fail; \
28 *(dst) = d32 + (min); \
29 ++src; \
30})
31#define test_decode64_uint32() ((void)0)
32#define FULL_PARAMS(...)
33
34#else
35
36#define FULL_PARAMS(...) __VA_ARGS__
37
38/* Not inlining:
39 * de/encode64 functions are only used to read
40 * yescrypt_params_t field, and convert salt to binary -
41 * both of these are negligible compared to main hashing operation
42 */
43static NOINLINE const uint8_t *decode64_uint32(
44 uint32_t *dst,
45 const uint8_t *src, uint32_t val)
46{
47 uint32_t start = 0, end = 47, bits = 0;
48 uint32_t c;
49
50 if (!src) /* previous decode failed already? */
51 goto fail;
52
53 c = a2i64(*src++);
54 if (c > 63)
55 goto fail;
56
57// The encoding of number N:
58// start = 0 end = 47
59// If N < 48, it is encoded verbatim, else
60// N -= 48
61// start = end+1 = 48
62// end += (64-end)/2 = 55
63// If N < (end+1-start)<<6 = 8<<6, it is encoded as 48+(N>>6)|low6bits (that is, 48...55|<6bit>), else
64// N -= 8<<6
65// start = end+1 = 56
66// end += (64-end)/2 = 59
67// If N < (end+1-start)<<2*6 = 4<<12, it is encoded as 56+(N>>2*6)|low12bits (that is, 56...59|<6bit>|<6bit>), else
68// ...same for 60..61|<6bit>|<6bit>|<6bit>
69// .......same for 62|<6bit>|<6bit>|<6bit>|<6bit>
70// .......same for 63|<6bit>|<6bit>|<6bit>|<6bit>|<6bit>
71 dbg_dec64("c:%d val:0x%08x", (int)c, (unsigned)val);
72 while (c > end) {
73 dbg_dec64("c:%d > end:%d", (int)c, (int)end);
74 val += (end + 1 - start) << bits;
75 dbg_dec64("val+=0x%08x", (int)((end + 1 - start) << bits));
76 dbg_dec64(" val:0x%08x", (unsigned)val);
77 start = end + 1;
78 end += (64 - end) / 2;
79 bits += 6;
80 dbg_dec64("start=%d", (int)start);
81 dbg_dec64("end=%d", (int)end);
82 dbg_dec64("bits=%d", (int)bits);
83 }
84
85 val += (c - start) << bits;
86 dbg_dec64("final val+=0x%08x", (int)((c - start) << bits));
87 dbg_dec64(" val:0x%08x", (unsigned)val);
88
89 while (bits != 0) {
90 c = a2i64(*src++);
91 if (c > 63)
92 goto fail;
93 bits -= 6;
94 val += c << bits;
95 dbg_dec64("low bits val+=0x%08x", (int)(c << bits));
96 dbg_dec64(" val:0x%08x", (unsigned)val);
97 }
98 ret:
99 *dst = val;
100 return src;
101 fail:
102 val = 0;
103 src = NULL;
104 goto ret;
105}
106
107#if TEST_DECODE64
108static void test_decode64_uint32(void)
109{
110 const uint8_t *src, *end;
111 uint32_t u32;
112 int a = 48;
113 int b = 8<<6; // 0x0200
114 int c = 4<<12; // 0x04000
115 int d = 2<<18; // 0x080000
116 int e = 1<<24; // 0x1000000
117
118 src = (void*)"wzzz";
119 end = decode64_uint32(&u32, src, 0);
120 if (u32 != 0x0003ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
121 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
122 src = (void*)"xzzz";
123 end = decode64_uint32(&u32, src, 0);
124 if (u32 != 0x0007ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
125 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
126 // Note how the last representable "x---" encoding, 0x7ffff, is exactly d-1!
127 // And if we now increment it, we get:
128 src = (void*)"y....";
129 end = decode64_uint32(&u32, src, 0);
130 if (u32 != 0x00000000+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
131 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
132 src = (void*)"yzzzz";
133 end = decode64_uint32(&u32, src, 0);
134 if (u32 != 0x00ffffff+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
135 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
136
137 src = (void*)"zzzzzz";
138 end = decode64_uint32(&u32, src, 0);
139 if (u32 != 0x3fffffff+e+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
140 if (end != src + 6) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
141
142 bb_error_msg("test_decode64_uint32() OK");
143}
144#else
145# define test_decode64_uint32() ((void)0)
146#endif
147
148#endif /* !RESTRICTED_PARAMS */
149
150#if 1
151static const uint8_t *decode64(
152 uint8_t *dst, size_t *dstlen,
153 const uint8_t *src)
154{
155 unsigned dstpos = 0;
156
157 dbg_dec64("src:'%s'", src);
158 for (;;) {
159 uint32_t c, value = 0;
160 int bits = 0;
161 while (*src != '\0' && *src != '$') {
162 c = a2i64(*src);
163 if (c > 63) { /* bad ascii64 char, stop decoding at it */
164 break;
165 }
166 src++;
167 value |= c << bits;
168 bits += 6;
169 if (bits == 24) /* got 4 chars */
170 goto store;
171 }
172 /* we read entire src, or met a non-ascii64 char (such as "$") */
173 if (bits == 0)
174 break;
175 /* else: we got last, partial bit block - store it */
176 store:
177 dbg_dec64(" storing bits:%d dstpos:%u v:%08x", bits, dstpos, (int)SWAP_BE32(value)); //BE to see lsb first
178 for (;;) {
179 if ((*src == '\0' || *src == '$')
180 && value == 0 && bits < 8
181 ) {
182 /* Example: mkpasswd PWD '$y$j9T$123':
183 * the "123" is bits:18 value:03,51,00
184 * is considered to be 2 bytes, not 3!
185 *
186 * '$y$j9T$zzz' in upstream fails outright (3rd byte isn't zero).
187 * IOW: for upstream, validity of salt depends on VALUE,
188 * not just size of salt. Which is a bug.
189 * The '$y$j9T$zzz.' salt is the same
190 * (it adds 6 zero msbits) but upstream works with it,
191 * thus '$y$j9T$zzz' should work too and give the same result.
192 */
193 goto end;
194 }
195 if (dstpos >= *dstlen) {
196 dbg_dec64(" ERR: bits:%d dstpos:%u dst[] is too small", bits, dstpos);
197 goto fail;
198 }
199 *dst++ = value;
200 dstpos++;
201 value >>= 8;
202 bits -= 8;
203 if (bits <= 0) /* can get negative, if we e.g. had 6 bits */
204 break;
205 }
206 if (*src == '\0' || *src == '$')
207 break;
208 }
209 end:
210 *dstlen = dstpos;
211 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
212 return src;
213 fail:
214 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
215 return NULL;
216}
217#else
218/* Buggy (and larger) original code */
219static const uint8_t *decode64(
220 uint8_t *dst, size_t *dstlen,
221 const uint8_t *src, size_t srclen)
222{
223 size_t dstpos = 0;
224
225 while (dstpos <= *dstlen && srclen) {
226 uint32_t value = 0, bits = 0;
227 while (srclen--) {
228 uint32_t c = a2i64(*src);
229 if (c > 63) {
230 srclen = 0;
231 break;
232 }
233 src++;
234 value |= c << bits;
235 bits += 6;
236 if (bits >= 24)
237 break;
238 }
239 if (!bits)
240 break;
241 if (bits < 12) /* must have at least one full byte */
242 goto fail;
243 dbg_dec64(" storing bits:%d v:%08x", (int)bits, (int)SWAP_BE32(value)); //BE to see lsb first
244 while (dstpos++ < *dstlen) {
245 *dst++ = value;
246 value >>= 8;
247 bits -= 8;
248 if (bits < 8) { /* 2 or 4 */
249 if (value) /* must be 0 */
250 goto fail;
251 bits = 0;
252 break;
253 }
254 }
255 if (bits)
256 goto fail;
257 }
258
259 if (!srclen && dstpos <= *dstlen) {
260 *dstlen = dstpos;
261 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
262 return src;
263 }
264 fail:
265 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
266 return NULL;
267}
268#endif
269
270static char *encode64(
271 char *dst, size_t dstlen,
272 const uint8_t *src, size_t srclen)
273{
274 while (srclen) {
275 uint32_t value = 0, b = 0;
276 do {
277 value |= (uint32_t)(*src++ << b);
278 b += 8;
279 srclen--;
280 } while (srclen && b < 24);
281
282 b >>= 3; /* number of bits to number of bytes */
283 b++; /* 1, 2 or 3 bytes will become 2, 3 or 4 ascii64 chars */
284 dstlen -= b;
285 if ((ssize_t)dstlen <= 0)
286 return NULL;
287 dst = num2str64_lsb_first(dst, value, b);
288 }
289 *dst = '\0';
290 return dst;
291}
292
293char *yescrypt_r(
294 const uint8_t *passwd, size_t passwdlen,
295 const uint8_t *setting,
296 char *buf, size_t buflen)
297{
298 struct {
299 yescrypt_ctx_t yctx[1];
300 unsigned char hashbin32[32];
301 } u;
302#define yctx u.yctx
303#define hashbin32 u.hashbin32
304 char *dst;
305 const uint8_t *src, *saltend;
306 size_t need, prefixlen;
307 uint32_t u32;
308
309 test_decode64_uint32();
310
311 memset(yctx, 0, sizeof(yctx));
312 FULL_PARAMS(yctx->param.p = 1;)
313
314 /* we assume setting starts with "$y$" (caller must ensure this) */
315 src = setting + 3;
316
317 src = decode64_uint32(&yctx->param.flags, src, 0);
318 /* "j9T" returns: 0x2f */
319 //if (!src)
320 // goto fail;
321
322 if (yctx->param.flags < YESCRYPT_RW) {
323 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
324 goto fail; // bbox: we don't support scrypt - only yescrypt
325 } else if (yctx->param.flags <= YESCRYPT_RW + (YESCRYPT_RW_FLAVOR_MASK >> 2)) {
326 /* "j9T" sets flags to 0xb6 */
327 yctx->param.flags = YESCRYPT_RW + ((yctx->param.flags - YESCRYPT_RW) << 2);
328 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
329 dbg(" YESCRYPT_RW:%u", !!(yctx->param.flags & YESCRYPT_RW));
330 dbg((yctx->param.flags & YESCRYPT_RW_FLAVOR_MASK) ==
331 (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
332 ? " YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K"
333 : " flags are not standard"
334 );
335 } else {
336 goto fail;
337 }
338
339 src = decode64_uint32(&u32, src, 1);
340 if (/*!src ||*/ u32 > 63)
341 goto fail;
342 yctx->param.N = (uint64_t)1 << u32;
343 /* "j9T" sets to 4096 (1<<12) */
344 dbg("yctx->param.N=%llu (1<<%u)", (unsigned long long)yctx->param.N, (unsigned)u32);
345
346 src = decode64_uint32(&yctx->param.r, src, 1);
347 /* "j9T" sets to 32 */
348 dbg("yctx->param.r=%u", yctx->param.r);
349
350 if (!src)
351 goto fail;
352 if (*src != '$') {
353#if RESTRICTED_PARAMS
354 goto fail;
355#else
356 src = decode64_uint32(&u32, src, 1);
357 dbg("yescrypt has extended params:0x%x", (unsigned)u32);
358 if (u32 & 1)
359 src = decode64_uint32(&yctx->param.p, src, 2);
360 if (u32 & 2)
361 src = decode64_uint32(&yctx->param.t, src, 1);
362 if (u32 & 4)
363 src = decode64_uint32(&yctx->param.g, src, 1);
364 if (u32 & 8) {
365 src = decode64_uint32(&u32, src, 1);
366 if (/*!src ||*/ u32 > 63)
367 goto fail;
368 yctx->param.NROM = (uint64_t)1 << u32;
369 }
370 if (!src)
371 goto fail;
372 if (*src != '$')
373 goto fail;
374#endif
375 }
376
377 yctx->saltlen = sizeof(yctx->salt);
378 src++; /* now points to salt */
379 saltend = decode64(yctx->salt, &yctx->saltlen, src);
380 if (!saltend || (*saltend != '\0' && *saltend != '$'))
381 goto fail; /* salt[] is too small, or bad char during decode */
382 dbg_dec64("salt is %d ascii64 chars -> %d bytes (in binary)", (int)(saltend - src), (int)yctx->saltlen);
383
384 prefixlen = saltend - setting;
385 need = prefixlen + 1 + YESCRYPT_HASH_LEN + 1;
386 if (need > buflen /*overflow is quite unlikely: || need < prefixlen*/)
387 goto fail;
388
389 if (yescrypt_kdf32(yctx, passwd, passwdlen, hashbin32)) {
390 dbg("error in yescrypt_kdf32");
391 goto fail;
392 }
393
394 dst = mempcpy(buf, setting, prefixlen);
395 *dst++ = '$';
396 dst = encode64(dst, buflen - (dst - buf), hashbin32, sizeof(hashbin32));
397 if (!dst)
398 goto fail;
399 ret:
400 free_region(yctx->local);
401 explicit_bzero(&u, sizeof(u));
402 return buf;
403 fail:
404 buf = NULL;
405 goto ret;
406#undef yctx
407#undef hashbin32
408}
diff --git a/libbb/yescrypt/alg-yescrypt-kdf.c b/libbb/yescrypt/alg-yescrypt-kdf.c
new file mode 100644
index 000000000..a9a1bd591
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt-kdf.c
@@ -0,0 +1,1212 @@
1/*-
2 * Copyright 2009 Colin Percival
3 * Copyright 2012-2018 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * This file was originally written by Colin Percival as part of the Tarsnap
28 * online backup system.
29 */
30
31#if __STDC_VERSION__ >= 199901L
32/* Have restrict */
33#elif defined(__GNUC__)
34#define restrict __restrict
35#else
36#define restrict
37#endif
38
39#ifdef __GNUC__
40#define unlikely(exp) __builtin_expect(exp, 0)
41#else
42#define unlikely(exp) (exp)
43#endif
44
45typedef union {
46 uint32_t w[16];
47 uint64_t d[8];
48} salsa20_blk_t;
49
50static void salsa20_simd_shuffle(
51 const salsa20_blk_t *Bin,
52 salsa20_blk_t *Bout)
53{
54#define COMBINE(out, in1, in2) \
55do { \
56 Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); \
57} while (0)
58 COMBINE(0, 0, 2);
59 COMBINE(1, 5, 7);
60 COMBINE(2, 2, 4);
61 COMBINE(3, 7, 1);
62 COMBINE(4, 4, 6);
63 COMBINE(5, 1, 3);
64 COMBINE(6, 6, 0);
65 COMBINE(7, 3, 5);
66#undef COMBINE
67}
68
69static void salsa20_simd_unshuffle(
70 const salsa20_blk_t *Bin,
71 salsa20_blk_t *Bout)
72{
73#define UNCOMBINE(out, in1, in2) \
74do { \
75 Bout->w[out * 2] = Bin->d[in1]; \
76 Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; \
77} while (0)
78 UNCOMBINE(0, 0, 6);
79 UNCOMBINE(1, 5, 3);
80 UNCOMBINE(2, 2, 0);
81 UNCOMBINE(3, 7, 5);
82 UNCOMBINE(4, 4, 2);
83 UNCOMBINE(5, 1, 7);
84 UNCOMBINE(6, 6, 4);
85 UNCOMBINE(7, 3, 1);
86#undef UNCOMBINE
87}
88
89#define DECL_X \
90 salsa20_blk_t X
91#define DECL_Y \
92 salsa20_blk_t Y
93
94#if KDF_UNROLL_COPY
95#define COPY(out, in) \
96do { \
97 (out).d[0] = (in).d[0]; \
98 (out).d[1] = (in).d[1]; \
99 (out).d[2] = (in).d[2]; \
100 (out).d[3] = (in).d[3]; \
101 (out).d[4] = (in).d[4]; \
102 (out).d[5] = (in).d[5]; \
103 (out).d[6] = (in).d[6]; \
104 (out).d[7] = (in).d[7]; \
105} while (0)
106#else
107#define COPY(out, in) \
108do { \
109 memcpy((out).d, (in).d, sizeof((in).d)); \
110} while (0)
111#endif
112
113#define READ_X(in) COPY(X, in)
114#define WRITE_X(out) COPY(out, X)
115
116/**
117 * salsa20(B):
118 * Apply the Salsa20 core to the provided block.
119 */
120static void salsa20(salsa20_blk_t *restrict B,
121 salsa20_blk_t *restrict Bout,
122 uint32_t doublerounds)
123{
124 salsa20_blk_t X;
125#define x X.w
126
127 salsa20_simd_unshuffle(B, &X);
128
129 do {
130#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
131 /* Operate on columns */
132#if KDF_UNROLL_SALSA20
133 x[ 4] ^= R(x[ 0]+x[12], 7); // x[j] ^= R(x[k]+x[l], CONST)
134 x[ 8] ^= R(x[ 4]+x[ 0], 9);
135 x[12] ^= R(x[ 8]+x[ 4],13);
136 x[ 0] ^= R(x[12]+x[ 8],18);
137
138 x[ 9] ^= R(x[ 5]+x[ 1], 7);
139 x[13] ^= R(x[ 9]+x[ 5], 9);
140 x[ 1] ^= R(x[13]+x[ 9],13);
141 x[ 5] ^= R(x[ 1]+x[13],18);
142
143 x[14] ^= R(x[10]+x[ 6], 7);
144 x[ 2] ^= R(x[14]+x[10], 9);
145 x[ 6] ^= R(x[ 2]+x[14],13);
146 x[10] ^= R(x[ 6]+x[ 2],18);
147
148 x[ 3] ^= R(x[15]+x[11], 7);
149 x[ 7] ^= R(x[ 3]+x[15], 9);
150 x[11] ^= R(x[ 7]+x[ 3],13);
151 x[15] ^= R(x[11]+x[ 7],18);
152#else
153 {
154 unsigned j, k, l;
155 j = 4; k = 0; l = 12;
156 for (;;) {
157 uint32_t t;
158 x[j] ^= ({ t = x[k] + x[l]; R(t, 7); }); l = k; k = j; j = (j+4) & 0xf;
159 x[j] ^= ({ t = x[k] + x[l]; R(t, 9); }); l = k; k = j; j = (j+4) & 0xf;
160 x[j] ^= ({ t = x[k] + x[l]; R(t,13); }); l = k; k = j; j = (j+4) & 0xf;
161 x[j] ^= ({ t = x[k] + x[l]; R(t,18); });
162 if (j == 15) break;
163 l = j + 1; k = j + 5; j = (j+9) & 0xf;
164 }
165 }
166#endif
167 /* Operate on rows */
168#if KDF_UNROLL_SALSA20
169// i=0 n=0
170 x[ 1] ^= R(x[ 0]+x[ 3], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
171 x[ 2] ^= R(x[ 1]+x[ 0], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
172 x[ 3] ^= R(x[ 2]+x[ 1],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
173 x[ 0] ^= R(x[ 3]+x[ 2],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
174// i=4 n=1 ^^^j^^^ ^^^k^^^ ^^^l^^^
175 x[ 6] ^= R(x[ 5]+x[ 4], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
176 x[ 7] ^= R(x[ 6]+x[ 5], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
177 x[ 4] ^= R(x[ 7]+x[ 6],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
178 x[ 5] ^= R(x[ 4]+x[ 7],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
179// i=8 n=2
180 x[11] ^= R(x[10]+x[ 9], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
181 x[ 8] ^= R(x[11]+x[10], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
182 x[ 9] ^= R(x[ 8]+x[11],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
183 x[10] ^= R(x[ 9]+x[ 8],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
184// i=12 n=3
185 x[12] ^= R(x[15]+x[14], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
186 x[13] ^= R(x[12]+x[15], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
187 x[14] ^= R(x[13]+x[12],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
188 x[15] ^= R(x[14]+x[13],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
189#else
190 {
191 unsigned j, k, l;
192 uint32_t *xrow;
193 j = 1; k = 0; l = 3;
194 xrow = &x[0];
195 for (;;) {
196 uint32_t t;
197 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 7); }); l = k; k = j; j = (j+1) & 3;
198 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 9); }); l = k; k = j; j = (j+1) & 3;
199 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,13); }); l = k; k = j; j = (j+1) & 3;
200 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,18); });
201 if (j == 3) break;
202 l = j; k = j + 1; j = (j+2) & 3;
203 xrow += 4;
204 }
205 }
206#endif
207
208#undef R
209 } while (--doublerounds);
210#undef x
211
212 {
213 uint32_t i;
214 salsa20_simd_shuffle(&X, Bout);
215 for (i = 0; i < 16; i++) {
216 // bbox: note: was unrolled x4
217 B->w[i] = Bout->w[i] += B->w[i];
218 }
219 }
220#if 0
221 /* Too expensive */
222 explicit_bzero(&X, sizeof(X));
223#endif
224}
225
226/**
227 * Apply the Salsa20/2 core to the block provided in X.
228 */
229#define SALSA20_2(out) \
230 salsa20(&X, &out, 1)
231
232#if 0
233#define XOR(out, in1, in2) \
234do { \
235 (out).d[0] = (in1).d[0] ^ (in2).d[0]; \
236 (out).d[1] = (in1).d[1] ^ (in2).d[1]; \
237 (out).d[2] = (in1).d[2] ^ (in2).d[2]; \
238 (out).d[3] = (in1).d[3] ^ (in2).d[3]; \
239 (out).d[4] = (in1).d[4] ^ (in2).d[4]; \
240 (out).d[5] = (in1).d[5] ^ (in2).d[5]; \
241 (out).d[6] = (in1).d[6] ^ (in2).d[6]; \
242 (out).d[7] = (in1).d[7] ^ (in2).d[7]; \
243} while (0)
244#else
245#define XOR(out, in1, in2) \
246do { \
247 xorbuf64_3_aligned64(&(out).d, &(in1).d, &(in2).d); \
248} while (0)
249#endif
250
251#define XOR_X(in) XOR(X, X, in)
252#define XOR_X_2(in1, in2) XOR(X, in1, in2)
253#define XOR_X_WRITE_XOR_Y_2(out, in) \
254do { \
255 XOR(Y, out, in); \
256 COPY(out, Y); \
257 XOR(X, X, Y); \
258} while (0)
259
260/**
261 * Apply the Salsa20/8 core to the block provided in X ^ in.
262 */
263#define SALSA20_8_XOR_MEM(in, out) \
264do { \
265 XOR_X(in); \
266 salsa20(&X, &out, 4); \
267} while (0)
268
269#define INTEGERIFY ((uint32_t)X.d[0])
270
271/**
272 * blockmix_salsa8(Bin, Bout, r):
273 * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
274 * bytes in length; the output Bout must also be the same size.
275 */
276static void blockmix_salsa8(
277 const salsa20_blk_t *restrict Bin,
278 salsa20_blk_t *restrict Bout,
279 size_t r)
280{
281 size_t i;
282 DECL_X;
283
284 READ_X(Bin[r * 2 - 1]);
285 for (i = 0; i < r; i++) {
286 SALSA20_8_XOR_MEM(Bin[i * 2], Bout[i]);
287 SALSA20_8_XOR_MEM(Bin[i * 2 + 1], Bout[r + i]);
288 }
289}
290
291static uint32_t blockmix_salsa8_xor(
292 const salsa20_blk_t *restrict Bin1,
293 const salsa20_blk_t *restrict Bin2,
294 salsa20_blk_t *restrict Bout,
295 size_t r)
296{
297 size_t i;
298 DECL_X;
299
300 XOR_X_2(Bin1[r * 2 - 1], Bin2[r * 2 - 1]);
301 for (i = 0; i < r; i++) {
302 XOR_X(Bin1[i * 2]);
303 SALSA20_8_XOR_MEM(Bin2[i * 2], Bout[i]);
304 XOR_X(Bin1[i * 2 + 1]);
305 SALSA20_8_XOR_MEM(Bin2[i * 2 + 1], Bout[r + i]);
306 }
307
308 return INTEGERIFY;
309}
310
311/* This is tunable */
312#define Swidth 8
313
314/* Not tunable in this implementation, hard-coded in a few places */
315#define PWXsimple 2
316#define PWXgather 4
317
318/* Derived values. Not tunable except via Swidth above. */
319#define PWXbytes (PWXgather * PWXsimple * 8)
320#define Sbytes (3 * (1 << Swidth) * PWXsimple * 8)
321#define Smask (((1 << Swidth) - 1) * PWXsimple * 8)
322#define Smask2 (((uint64_t)Smask << 32) | Smask)
323
324#define DECL_SMASK2REG do {} while (0)
325#define FORCE_REGALLOC_3 do {} while (0)
326#define MAYBE_MEMORY_BARRIER do {} while (0)
327
328#define PWXFORM_SIMD(x0, x1) \
329do { \
330 uint64_t x = x0 & Smask2; \
331 uint64_t *p0 = (uint64_t *)(S0 + (uint32_t)x); \
332 uint64_t *p1 = (uint64_t *)(S1 + (x >> 32)); \
333 x0 = ((x0 >> 32) * (uint32_t)x0 + p0[0]) ^ p1[0]; \
334 x1 = ((x1 >> 32) * (uint32_t)x1 + p0[1]) ^ p1[1]; \
335} while (0)
336
337#if KDF_UNROLL_PWXFORM_ROUND
338#define PWXFORM_ROUND \
339do { \
340 PWXFORM_SIMD(X.d[0], X.d[1]); \
341 PWXFORM_SIMD(X.d[2], X.d[3]); \
342 PWXFORM_SIMD(X.d[4], X.d[5]); \
343 PWXFORM_SIMD(X.d[6], X.d[7]); \
344} while (0)
345#else
346#define PWXFORM_ROUND \
347do { \
348 for (int pwxi=0; pwxi<8; pwxi+=2) \
349 PWXFORM_SIMD(X.d[pwxi], X.d[pwxi + 1]); \
350} while (0)
351#endif
352
353/*
354 * This offset helps address the 256-byte write block via the single-byte
355 * displacements encodable in x86(-64) instructions. It is needed because the
356 * displacements are signed. Without it, we'd get 4-byte displacements for
357 * half of the writes. Setting it to 0x80 instead of 0x7c would avoid needing
358 * a displacement for one of the writes, but then the LEA instruction would
359 * need a 4-byte displacement.
360 */
361#define PWXFORM_WRITE_OFFSET 0x7c
362
363#define PWXFORM_WRITE \
364do { \
365 WRITE_X(*(salsa20_blk_t *)(Sw - PWXFORM_WRITE_OFFSET)); \
366 Sw += 64; \
367} while (0)
368
369#if KDF_UNROLL_PWXFORM
370#define PWXFORM \
371do { \
372 uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \
373 FORCE_REGALLOC_3; \
374 MAYBE_MEMORY_BARRIER; \
375 PWXFORM_ROUND; \
376 PWXFORM_ROUND; PWXFORM_WRITE; \
377 PWXFORM_ROUND; PWXFORM_WRITE; \
378 PWXFORM_ROUND; PWXFORM_WRITE; \
379 PWXFORM_ROUND; PWXFORM_WRITE; \
380 PWXFORM_ROUND; \
381 w = (w + 64 * 4) & Smask2; \
382 { \
383 uint8_t *Stmp = S2; \
384 S2 = S1; \
385 S1 = S0; \
386 S0 = Stmp; \
387 } \
388} while (0)
389#else
390#define PWXFORM \
391do { \
392 uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \
393 FORCE_REGALLOC_3; \
394 MAYBE_MEMORY_BARRIER; \
395 PWXFORM_ROUND; \
396 for (int pwxj=0; pwxj<4; pwxj++) {\
397 PWXFORM_ROUND; PWXFORM_WRITE; \
398 } \
399 PWXFORM_ROUND; \
400 w = (w + 64 * 4) & Smask2; \
401 { \
402 uint8_t *Stmp = S2; \
403 S2 = S1; \
404 S1 = S0; \
405 S0 = Stmp; \
406 } \
407} while (0)
408#endif
409
410typedef struct {
411 uint8_t *S0, *S1, *S2;
412 size_t w;
413} pwxform_ctx_t;
414
415#define Salloc (Sbytes + ((sizeof(pwxform_ctx_t) + 63) & ~63U))
416
417/**
418 * blockmix_pwxform(Bin, Bout, r, S):
419 * Compute Bout = BlockMix_pwxform{salsa20/2, r, S}(Bin). The input Bin must
420 * be 128r bytes in length; the output Bout must also be the same size.
421 */
422static void blockmix(
423 const salsa20_blk_t *restrict Bin,
424 salsa20_blk_t *restrict Bout,
425 size_t r,
426 pwxform_ctx_t *restrict ctx)
427{
428 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
429 size_t w = ctx->w;
430 size_t i;
431 DECL_X;
432
433 /* Convert count of 128-byte blocks to max index of 64-byte block */
434 r = r * 2 - 1;
435
436 READ_X(Bin[r]);
437
438 DECL_SMASK2REG;
439
440 i = 0;
441 for (;;) {
442 XOR_X(Bin[i]);
443 PWXFORM;
444 if (unlikely(i >= r))
445 break;
446 WRITE_X(Bout[i]);
447 i++;
448 }
449
450 ctx->S0 = S0;
451 ctx->S1 = S1;
452 ctx->S2 = S2;
453 ctx->w = w;
454
455 SALSA20_2(Bout[i]);
456}
457
458static uint32_t blockmix_xor(
459 const salsa20_blk_t *Bin1,
460 const salsa20_blk_t *restrict Bin2,
461 salsa20_blk_t *Bout,
462 size_t r,
463 pwxform_ctx_t *restrict ctx)
464{
465 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
466 size_t w = ctx->w;
467 size_t i;
468 DECL_X;
469
470 /* Convert count of 128-byte blocks to max index of 64-byte block */
471 r = r * 2 - 1;
472
473 XOR_X_2(Bin1[r], Bin2[r]);
474
475 DECL_SMASK2REG;
476
477 i = 0;
478 r--;
479 for (;;) {
480 XOR_X(Bin1[i]);
481 XOR_X(Bin2[i]);
482 PWXFORM;
483 if (unlikely(i > r))
484 break;
485 WRITE_X(Bout[i]);
486 i++;
487 }
488
489 ctx->S0 = S0;
490 ctx->S1 = S1;
491 ctx->S2 = S2;
492 ctx->w = w;
493
494 SALSA20_2(Bout[i]);
495
496 return INTEGERIFY;
497}
498
499static uint32_t blockmix_xor_save(
500 salsa20_blk_t *restrict Bin1out,
501 salsa20_blk_t *restrict Bin2,
502 size_t r,
503 pwxform_ctx_t *restrict ctx)
504{
505 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
506 size_t w = ctx->w;
507 size_t i;
508 DECL_X;
509 DECL_Y;
510
511 /* Convert count of 128-byte blocks to max index of 64-byte block */
512 r = r * 2 - 1;
513
514 XOR_X_2(Bin1out[r], Bin2[r]);
515
516 DECL_SMASK2REG;
517
518 i = 0;
519 r--;
520 for (;;) {
521 XOR_X_WRITE_XOR_Y_2(Bin2[i], Bin1out[i]);
522 PWXFORM;
523 if (unlikely(i > r))
524 break;
525 WRITE_X(Bin1out[i]);
526 i++;
527 }
528
529 ctx->S0 = S0;
530 ctx->S1 = S1;
531 ctx->S2 = S2;
532 ctx->w = w;
533
534 SALSA20_2(Bin1out[i]);
535
536 return INTEGERIFY;
537}
538
539/**
540 * integerify(B, r):
541 * Return the result of parsing B_{2r-1} as a little-endian integer.
542 */
543static inline uint32_t integerify(const salsa20_blk_t *B, size_t r)
544{
545/*
546 * Our 64-bit words are in host byte order, which is why we don't just read
547 * w[0] here (would be wrong on big-endian). Also, our 32-bit words are
548 * SIMD-shuffled (so the next 32 bits would be part of d[6]), but currently
549 * this does not matter as we only care about the least significant 32 bits.
550 */
551 return (uint32_t)B[2 * r - 1].d[0];
552}
553
554/**
555 * smix1(B, r, N, flags, V, NROM, VROM, XY, ctx):
556 * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in
557 * length; the temporary storage V must be 128rN bytes in length; the temporary
558 * storage XY must be 128r+64 bytes in length. N must be even and at least 4.
559 * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY
560 * to a multiple of at least 16 bytes.
561 */
562#if DISABLE_NROM_CODE
563#define smix1(B,r,N,flags,V,NROM,VROM,XY,ctx) \
564 smix1(B,r,N,flags,V,XY,ctx)
565#endif
566static void smix1(uint8_t *B, size_t r, uint32_t N,
567 uint32_t flags,
568 salsa20_blk_t *V,
569 uint32_t NROM, const salsa20_blk_t *VROM,
570 salsa20_blk_t *XY,
571 pwxform_ctx_t *ctx)
572{
573#if DISABLE_NROM_CODE
574 uint32_t NROM = 0;
575 const salsa20_blk_t *VROM = NULL;
576#endif
577 size_t s = 2 * r;
578 salsa20_blk_t *X = V, *Y = &V[s];
579 uint32_t i, j;
580
581 for (i = 0; i < 2 * r; i++) {
582 const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64];
583 salsa20_blk_t *tmp = Y;
584 salsa20_blk_t *dst = &X[i];
585 size_t k;
586 for (k = 0; k < 16; k++)
587 tmp->w[k] = SWAP_LE32(src->w[k]);
588 salsa20_simd_shuffle(tmp, dst);
589 }
590
591 if (VROM) {
592 uint32_t n;
593 const salsa20_blk_t *V_j;
594
595 V_j = &VROM[(NROM - 1) * s];
596 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
597 V_j = &VROM[j * s];
598 X = Y + s;
599 j = blockmix_xor(Y, V_j, X, r, ctx);
600
601 for (n = 2; n < N; n <<= 1) {
602 uint32_t m = (n < N / 2) ? n : (N - 1 - n);
603 for (i = 1; i < m; i += 2) {
604 j &= n - 1;
605 j += i - 1;
606 V_j = &V[j * s];
607 Y = X + s;
608 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
609 V_j = &VROM[j * s];
610 X = Y + s;
611 j = blockmix_xor(Y, V_j, X, r, ctx);
612 }
613 }
614 n >>= 1;
615
616 j &= n - 1;
617 j += N - 2 - n;
618 V_j = &V[j * s];
619 Y = X + s;
620 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
621 V_j = &VROM[j * s];
622 blockmix_xor(Y, V_j, XY, r, ctx);
623 } else if (flags & YESCRYPT_RW) {
624//can't use flags___YESCRYPT_RW, smix1() may be called with flags = 0
625 uint32_t n;
626 salsa20_blk_t *V_j;
627
628 blockmix(X, Y, r, ctx);
629 X = Y + s;
630 blockmix(Y, X, r, ctx);
631 j = integerify(X, r);
632
633 for (n = 2; n < N; n <<= 1) {
634 uint32_t m = (n < N / 2) ? n : (N - 1 - n);
635 for (i = 1; i < m; i += 2) {
636 Y = X + s;
637 j &= n - 1;
638 j += i - 1;
639 V_j = &V[j * s];
640 j = blockmix_xor(X, V_j, Y, r, ctx);
641 j &= n - 1;
642 j += i;
643 V_j = &V[j * s];
644 X = Y + s;
645 j = blockmix_xor(Y, V_j, X, r, ctx);
646 }
647 }
648 n >>= 1;
649
650 j &= n - 1;
651 j += N - 2 - n;
652 V_j = &V[j * s];
653 Y = X + s;
654 j = blockmix_xor(X, V_j, Y, r, ctx);
655 j &= n - 1;
656 j += N - 1 - n;
657 V_j = &V[j * s];
658 blockmix_xor(Y, V_j, XY, r, ctx);
659 } else {
660 N -= 2;
661 do {
662 blockmix_salsa8(X, Y, r);
663 X = Y + s;
664 blockmix_salsa8(Y, X, r);
665 Y = X + s;
666 } while ((N -= 2));
667
668 blockmix_salsa8(X, Y, r);
669 blockmix_salsa8(Y, XY, r);
670 }
671
672 for (i = 0; i < 2 * r; i++) {
673 const salsa20_blk_t *src = &XY[i];
674 salsa20_blk_t *tmp = &XY[s];
675 salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64];
676 size_t k;
677 for (k = 0; k < 16; k++)
678 tmp->w[k] = SWAP_LE32(src->w[k]);
679 salsa20_simd_unshuffle(tmp, dst);
680 }
681}
682
683/**
684 * smix2(B, r, N, Nloop, flags, V, NROM, VROM, XY, ctx):
685 * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in
686 * length; the temporary storage V must be 128rN bytes in length; the temporary
687 * storage XY must be 256r bytes in length. N must be a power of 2 and at
688 * least 2. Nloop must be even. The array V must be aligned to a multiple of
689 * 64 bytes, and arrays B and XY to a multiple of at least 16 bytes.
690 */
691#if DISABLE_NROM_CODE
692#define smix2(B,r,N,Nloop,flags,V,NROM,VROM,XY,ctx) \
693 smix2(B,r,N,Nloop,flags,V,XY,ctx)
694#endif
695static void smix2(uint8_t *B, size_t r, uint32_t N, uint64_t Nloop,
696 uint32_t flags,
697 salsa20_blk_t *V,
698 uint32_t NROM, const salsa20_blk_t *VROM,
699 salsa20_blk_t *XY,
700 pwxform_ctx_t *ctx)
701{
702#if DISABLE_NROM_CODE
703 uint32_t NROM = 0;
704 const salsa20_blk_t *VROM = NULL;
705#endif
706 size_t s = 2 * r;
707 salsa20_blk_t *X = XY, *Y = &XY[s];
708 uint32_t i, j;
709
710 if (Nloop == 0)
711 return;
712
713 for (i = 0; i < 2 * r; i++) {
714 const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64];
715 salsa20_blk_t *tmp = Y;
716 salsa20_blk_t *dst = &X[i];
717 size_t k;
718 for (k = 0; k < 16; k++)
719 tmp->w[k] = SWAP_LE32(src->w[k]);
720 salsa20_simd_shuffle(tmp, dst);
721 }
722
723 j = integerify(X, r) & (N - 1);
724
725/*
726 * Normally, VROM implies YESCRYPT_RW, but we check for these separately
727 * because our SMix resets YESCRYPT_RW for the smix2() calls operating on the
728 * entire V when p > 1.
729 */
730//and this is why bbox can't use flags___YESCRYPT_RW in this function
731 if (VROM && (flags & YESCRYPT_RW)) {
732 do {
733 salsa20_blk_t *V_j = &V[j * s];
734 const salsa20_blk_t *VROM_j;
735 j = blockmix_xor_save(X, V_j, r, ctx) & (NROM - 1);
736 VROM_j = &VROM[j * s];
737 j = blockmix_xor(X, VROM_j, X, r, ctx) & (N - 1);
738 } while (Nloop -= 2);
739 } else if (VROM) {
740 do {
741 const salsa20_blk_t *V_j = &V[j * s];
742 j = blockmix_xor(X, V_j, X, r, ctx) & (NROM - 1);
743 V_j = &VROM[j * s];
744 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
745 } while (Nloop -= 2);
746 } else if (flags & YESCRYPT_RW) {
747 do {
748 salsa20_blk_t *V_j = &V[j * s];
749 j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1);
750 V_j = &V[j * s];
751 j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1);
752 } while (Nloop -= 2);
753 } else if (ctx) {
754 do {
755 const salsa20_blk_t *V_j = &V[j * s];
756 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
757 V_j = &V[j * s];
758 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
759 } while (Nloop -= 2);
760 } else {
761 do {
762 const salsa20_blk_t *V_j = &V[j * s];
763 j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1);
764 V_j = &V[j * s];
765 j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1);
766 } while (Nloop -= 2);
767 }
768
769 for (i = 0; i < 2 * r; i++) {
770 const salsa20_blk_t *src = &X[i];
771 salsa20_blk_t *tmp = Y;
772 salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64];
773 size_t k;
774 for (k = 0; k < 16; k++)
775 tmp->w[k] = SWAP_LE32(src->w[k]);
776 salsa20_simd_unshuffle(tmp, dst);
777 }
778}
779
780/**
781 * p2floor(x):
782 * Largest power of 2 not greater than argument.
783 */
784static uint64_t p2floor(uint64_t x)
785{
786 uint64_t y;
787 while ((y = x & (x - 1)))
788 x = y;
789 return x;
790}
791
792/**
793 * smix(B, r, N, p, t, flags, V, NROM, VROM, XY, S, passwd):
794 * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the
795 * temporary storage V must be 128rN bytes in length; the temporary storage
796 * XY must be 256r or 256rp bytes in length (the larger size is required with
797 * OpenMP-enabled builds). N must be a power of 2 and at least 4. The array V
798 * must be aligned to a multiple of 64 bytes, and arrays B and XY to a multiple
799 * of at least 16 bytes (aligning them to 64 bytes as well saves cache lines
800 * and helps avoid false sharing in OpenMP-enabled builds when p > 1, but it
801 * might also result in cache bank conflicts).
802 */
803#if DISABLE_NROM_CODE
804#define smix(B,r,N,p,t,flags,V,NROM,VROM,XY,S,passwd) \
805 smix(B,r,N,p,t,flags,V,XY,S,passwd)
806#endif
807static void smix(uint8_t *B, size_t r, uint32_t N, uint32_t p, uint32_t t,
808 uint32_t flags,
809 salsa20_blk_t *V,
810 uint32_t NROM, const salsa20_blk_t *VROM,
811 salsa20_blk_t *XY,
812 uint8_t *S, uint8_t *passwd)
813{
814 size_t s = 2 * r;
815 uint32_t Nchunk;
816 uint64_t Nloop_all, Nloop_rw;
817 uint32_t i;
818
819 Nchunk = N / p;
820 Nloop_all = Nchunk;
821 if (flags___YESCRYPT_RW) {
822 if (t <= 1) {
823 if (t)
824 Nloop_all *= 2; /* 2/3 */
825 Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */
826 } else {
827 Nloop_all *= t - 1;
828 }
829 } else if (t) {
830 if (t == 1)
831 Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */
832 Nloop_all *= t;
833 }
834
835 Nloop_rw = 0;
836 if (flags___YESCRYPT_RW)
837 Nloop_rw = Nloop_all / p;
838
839 Nchunk &= ~(uint32_t)1; /* round down to even */
840 Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */
841 Nloop_rw++; Nloop_rw &= ~(uint64_t)1; /* round up to even */
842
843 for (i = 0; i < p; i++) {
844 uint32_t Vchunk = i * Nchunk;
845 uint32_t Np = (i < p - 1) ? Nchunk : (N - Vchunk);
846 uint8_t *Bp = &B[128 * r * i];
847 salsa20_blk_t *Vp = &V[Vchunk * s];
848 salsa20_blk_t *XYp = XY;
849 pwxform_ctx_t *ctx_i = NULL;
850 if (flags___YESCRYPT_RW) {
851 uint8_t *Si = S + i * Salloc;
852 smix1(Bp, 1, Sbytes / 128, 0 /* no flags */,
853 (salsa20_blk_t *)Si, 0, NULL, XYp, NULL);
854 ctx_i = (pwxform_ctx_t *)(Si + Sbytes);
855 ctx_i->S2 = Si;
856 ctx_i->S1 = Si + Sbytes / 3;
857 ctx_i->S0 = Si + Sbytes / 3 * 2;
858 ctx_i->w = 0;
859 if (i == 0)
860 hmac_block(
861 /* key,len: */ Bp + (128 * r - 64), 64,
862 /* hash fn: */ sha256_begin,
863 /* in,len: */ passwd, 32,
864 /* outbuf: */ passwd
865 );
866 }
867 smix1(Bp, r, Np, flags, Vp, NROM, VROM, XYp, ctx_i);
868 smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp,
869 NROM, VROM, XYp, ctx_i);
870 }
871
872 if (Nloop_all > Nloop_rw) {
873 for (i = 0; i < p; i++) {
874 uint8_t *Bp = &B[128 * r * i];
875 salsa20_blk_t *XYp = XY;
876 pwxform_ctx_t *ctx_i = NULL;
877 if (flags___YESCRYPT_RW) {
878 uint8_t *Si = S + i * Salloc;
879 ctx_i = (pwxform_ctx_t *)(Si + Sbytes);
880 }
881 smix2(Bp, r, N, Nloop_all - Nloop_rw,
882 flags & (uint32_t)~YESCRYPT_RW,
883 V, NROM, VROM, XYp, ctx_i);
884 }
885 }
886}
887
888/* Allocator code */
889
890static void alloc_region(yescrypt_region_t *region, size_t size)
891{
892 uint8_t *base;
893 int flags =
894# ifdef MAP_NOCORE /* huh? */
895 MAP_NOCORE |
896# endif
897 MAP_ANON | MAP_PRIVATE;
898
899 base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
900 if (base == MAP_FAILED)
901 bb_die_memory_exhausted();
902
903#if defined(MADV_HUGEPAGE)
904 /* Reduces mkpasswd qweRTY123@-+ '$y$jHT$123'
905 * (which allocates 4 Gbytes)
906 * run time from 10.543s to 5.635s
907 * Seen on linux-5.18.0.
908 */
909 madvise(base, size, MADV_HUGEPAGE);
910#endif
911 //region->base = base;
912 //region->base_size = size;
913 region->aligned = base;
914 region->aligned_size = size;
915}
916
917static void free_region(yescrypt_region_t *region)
918{
919 if (region->aligned)
920 munmap(region->aligned, region->aligned_size);
921 //region->base = NULL;
922 //region->base_size = 0;
923 region->aligned = NULL;
924 region->aligned_size = 0;
925}
926/**
927 * yescrypt_kdf_body(shared, local, passwd, passwdlen, salt, saltlen,
928 * flags, N, r, p, t, NROM, buf, buflen):
929 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
930 * p, buflen), or a revision of scrypt as requested by flags and shared, and
931 * write the result into buf.
932 *
933 * shared and flags may request special modes as described in yescrypt.h.
934 *
935 * local is the thread-local data structure, allowing to preserve and reuse a
936 * memory allocation across calls, thereby reducing its overhead.
937 *
938 * t controls computation time while not affecting peak memory usage.
939 *
940 * Return 0 on success; or -1 on error.
941 *
942 * This optimized implementation currently limits N to the range from 4 to
943 * 2^31, but other implementations might not.
944 */
945static int yescrypt_kdf32_body(
946 yescrypt_ctx_t *yctx,
947 const uint8_t *passwd, size_t passwdlen,
948 uint32_t flags, uint64_t N, uint32_t t,
949 uint8_t *buf32)
950{
951#if !DISABLE_NROM_CODE
952 const salsa20_blk_t *VROM;
953#endif
954 size_t B_size, V_size, XY_size, need;
955 uint8_t *B, *S;
956 salsa20_blk_t *V, *XY;
957 struct {
958 uint8_t sha256[32];
959 uint8_t dk[32];
960 } u;
961#define sha256 u.sha256
962#define dk u.dk
963 uint8_t *dkp = buf32;
964 uint32_t r, p;
965
966 /* Sanity-check parameters */
967 switch (flags___YESCRYPT_MODE_MASK) {
968 case 0: /* classic scrypt - can't have anything non-standard */
969 if (flags || t || YCTX_param_NROM)
970 goto out_EINVAL;
971 break;
972 case YESCRYPT_WORM:
973 if (flags != YESCRYPT_WORM || YCTX_param_NROM)
974 goto out_EINVAL;
975 break;
976 case YESCRYPT_RW:
977 if (flags != (flags & YESCRYPT_KNOWN_FLAGS))
978 goto out_EINVAL;
979#if PWXsimple == 2 && PWXgather == 4 && Sbytes == 12288
980 if ((flags & YESCRYPT_RW_FLAVOR_MASK) ==
981 (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 |
982 YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K))
983 break;
984#else
985#error "Unsupported pwxform settings"
986#endif
987 /* FALLTHRU */
988 default:
989 goto out_EINVAL;
990 }
991
992 r = YCTX_param_r;
993 p = YCTX_param_p;
994 if ((uint64_t)r * (uint64_t)p >= 1 << 30) {
995 dbg("r * n >= 2^30");
996 goto out_EINVAL;
997 }
998 if (N > UINT32_MAX) {
999 dbg("N > 0x%lx", (long)UINT32_MAX);
1000 goto out_EINVAL;
1001 }
1002 if (N <= 3
1003 || r < 1
1004 || p < 1
1005 ) {
1006 dbg("bad N, r or p");
1007 goto out_EINVAL;
1008 }
1009 if (r > SIZE_MAX / 256 / p
1010 || N > SIZE_MAX / 128 / r
1011 ) {
1012 /* 32-bit testcase: mkpasswd qweRTY123@-+ '$y$jHT$123'
1013 * (works on 64-bit, needs buffer > 4Gbytes)
1014 */
1015 dbg("r > SIZE_MAX / 256 / p? %c", "NY"[r > SIZE_MAX / 256 / p]);
1016 dbg("N > SIZE_MAX / 128 / r? %c", "NY"[N > SIZE_MAX / 128 / r]);
1017 goto out_EINVAL;
1018 }
1019 if (flags___YESCRYPT_RW) {
1020 /* p cannot be greater than SIZE_MAX/Salloc on 64-bit systems,
1021 but it can on 32-bit systems. */
1022#pragma GCC diagnostic push
1023#pragma GCC diagnostic ignored "-Wtype-limits"
1024 if (N / p <= 3 || p > SIZE_MAX / Salloc) {
1025 dbg("bad p:%ld", (long)p);
1026 goto out_EINVAL;
1027 }
1028#pragma GCC diagnostic pop
1029 }
1030
1031#if !DISABLE_NROM_CODE
1032 VROM = NULL;
1033 if (YCTX_param_NROM)
1034 goto out_EINVAL;
1035#endif
1036
1037 /* Allocate memory */
1038 V = NULL;
1039 V_size = (size_t)128 * r * N;
1040 need = V_size;
1041 B_size = (size_t)128 * r * p;
1042 need += B_size;
1043 if (need < B_size) {
1044 dbg("integer overflow at += B_size(%lu)", (long)B_size);
1045 goto out_EINVAL;
1046 }
1047 XY_size = (size_t)256 * r;
1048 need += XY_size;
1049 if (need < XY_size) {
1050 dbg("integer overflow at += XY_size(%lu)", (long)XY_size);
1051 goto out_EINVAL;
1052 }
1053 if (flags___YESCRYPT_RW) {
1054 size_t S_size = (size_t)Salloc * p;
1055 need += S_size;
1056 if (need < S_size) {
1057 dbg("integer overflow at += S_size(%lu)", (long)S_size);
1058 goto out_EINVAL;
1059 }
1060 }
1061 if (yctx->local->aligned_size < need) {
1062 free_region(yctx->local);
1063 alloc_region(yctx->local, need);
1064 dbg("allocated local:%lu 0x%lx", (long)need, (long)need);
1065 /* standard "j9T" params allocate 16Mbytes here */
1066 }
1067 if (flags & YESCRYPT_ALLOC_ONLY)
1068 return -3; /* expected "failure" */
1069 B = (uint8_t *)yctx->local->aligned;
1070 V = (salsa20_blk_t *)((uint8_t *)B + B_size);
1071 XY = (salsa20_blk_t *)((uint8_t *)V + V_size);
1072 S = NULL;
1073 if (flags___YESCRYPT_RW)
1074 S = (uint8_t *)XY + XY_size;
1075
1076 if (flags) {
1077 hmac_block(
1078 /* key,len: */ (const void*)"yescrypt-prehash", (flags & YESCRYPT_PREHASH) ? 16 : 8,
1079 /* hash fn: */ sha256_begin,
1080 /* in,len: */ passwd, passwdlen,
1081 /* outbuf: */ sha256
1082 );
1083 passwd = sha256;
1084 passwdlen = sizeof(sha256);
1085 }
1086
1087 PBKDF2_SHA256(passwd, passwdlen, yctx->salt, yctx->saltlen, 1, B, B_size);
1088
1089 if (flags)
1090 memcpy(sha256, B, sizeof(sha256));
1091
1092 if (p == 1 || (flags___YESCRYPT_RW)) {
1093 smix(B, r, N, p, t, flags, V, YCTX_param_NROM, VROM, XY, S, sha256);
1094 } else {
1095 uint32_t i;
1096 for (i = 0; i < p; i++) {
1097 smix(&B[(size_t)128 * r * i], r, N, 1, t, flags, V,
1098 YCTX_param_NROM, VROM, XY, NULL, NULL);
1099 }
1100 }
1101
1102 dkp = buf32;
1103 if (flags && /*buflen:*/32 < sizeof(dk)) {
1104 PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, dk, sizeof(dk));
1105 dkp = dk;
1106 }
1107
1108 PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf32, /*buflen:*/32);
1109
1110 /*
1111 * Except when computing classic scrypt, allow all computation so far
1112 * to be performed on the client. The final steps below match those of
1113 * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so
1114 * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of
1115 * SCRAM's use of SHA-1) would be usable with yescrypt hashes.
1116 */
1117 if (flags && !(flags & YESCRYPT_PREHASH)) {
1118 /* Compute ClientKey */
1119 hmac_block(
1120 /* key,len: */ dkp, sizeof(dk),
1121 /* hash fn: */ sha256_begin,
1122 /* in,len: */ "Client Key", 10,
1123 /* outbuf: */ sha256
1124 );
1125 /* Compute StoredKey */
1126 {
1127 size_t clen = /*buflen:*/32;
1128 if (clen > sizeof(dk))
1129 clen = sizeof(dk);
1130 if (sizeof(dk) != 32) { /* not true, optimize it out */
1131 sha256_block(sha256, sizeof(sha256), dk);
1132 memcpy(buf32, dk, clen);
1133 } else {
1134 sha256_block(sha256, sizeof(sha256), buf32);
1135 }
1136 }
1137 }
1138
1139 explicit_bzero(&u, sizeof(u));
1140
1141 /* Success! */
1142 return 0;
1143
1144 out_EINVAL:
1145 //bbox does not need this: errno = EINVAL;
1146 return -1;
1147#undef sha256
1148#undef dk
1149}
1150
1151/**
1152 * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, params,
1153 * buf, buflen):
1154 * Compute scrypt or its revision as requested by the parameters. The inputs
1155 * to this function are the same as those for yescrypt_kdf_body() above, with
1156 * the addition of g, which controls hash upgrades (0 for no upgrades so far).
1157 */
1158static
1159int yescrypt_kdf32(
1160 yescrypt_ctx_t *yctx,
1161 const uint8_t *passwd, size_t passwdlen,
1162 uint8_t *buf32)
1163{
1164 uint32_t flags = YCTX_param_flags;
1165 uint64_t N = YCTX_param_N;
1166 uint32_t r = YCTX_param_r;
1167 uint32_t p = YCTX_param_p;
1168 uint32_t t = YCTX_param_t;
1169 uint32_t g = YCTX_param_g;
1170 uint8_t dk32[32];
1171 int retval;
1172
1173 /* Support for hash upgrades has been temporarily removed */
1174 if (g) {
1175 //bbox does not need this: errno = EINVAL;
1176 return -1;
1177 }
1178
1179 if ((flags___YESCRYPT_RW)
1180 && p >= 1
1181 && N / p >= 0x100
1182 && N / p * r >= 0x20000
1183 ) {
1184 if (yescrypt_kdf32_body(yctx,
1185 passwd, passwdlen,
1186 flags | YESCRYPT_ALLOC_ONLY, N, t,
1187 buf32) != -3
1188 ) {
1189 dbg("yescrypt_kdf32_body: not -3");
1190 return -1;
1191 }
1192 retval = yescrypt_kdf32_body(yctx,
1193 passwd, passwdlen,
1194 flags | YESCRYPT_PREHASH, N >> 6, 0,
1195 dk32);
1196 if (retval) {
1197 dbg("yescrypt_kdf32_body(PREHASH):%d", retval);
1198 return retval;
1199 }
1200 passwd = dk32;
1201 passwdlen = sizeof(dk32);
1202 }
1203
1204 retval = yescrypt_kdf32_body(yctx,
1205 passwd, passwdlen,
1206 flags, N, t, buf32);
1207
1208 explicit_bzero(dk32, sizeof(dk32));
1209
1210 dbg("yescrypt_kdf32_body:%d", retval);
1211 return retval;
1212}
diff --git a/libbb/yescrypt/alg-yescrypt.h b/libbb/yescrypt/alg-yescrypt.h
new file mode 100644
index 000000000..b69843f5d
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt.h
@@ -0,0 +1,247 @@
1/*-
2 * Copyright 2009 Colin Percival
3 * Copyright 2013-2018 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * This file was originally written by Colin Percival as part of the Tarsnap
28 * online backup system.
29 */
30
31// busybox debug and size-reduction configuration
32
33#ifdef YESCRYPT_INTERNAL
34# if 1
35# define dbg(...) ((void)0)
36# else
37# define dbg(...) bb_error_msg(__VA_ARGS__)
38# endif
39# if 1
40# define dbg_dec64(...) ((void)0)
41# else
42# define dbg_dec64(...) bb_error_msg(__VA_ARGS__)
43# endif
44# define TEST_DECODE64 0
45#endif
46
47// Only accept one-char parameters in salt, and only first three?
48// Almost any reasonable yescrypt hashes in /etc/shadow should
49// only ever use "jXY" parameters which set N and r.
50// Fancy multi-byte-encoded wide integers are not needed for that.
51#define RESTRICTED_PARAMS 1
52// Note: if you enable the above, please also enable
53// YCTX_param_p, YCTX_param_t, YCTX_param_g, YCTX_param_NROM
54// optimizations, and DISABLE_NROM_CODE.
55
56#define DISABLE_NROM_CODE 1
57
58// How much we save by forcing "standard" value by commenting the next line:
59// 160 bytes
60//#define YCTX_param_flags yctx->param.flags
61// 260 bytes
62//#define flags___YESCRYPT_RW (flags & YESCRYPT_RW)
63// 140 bytes
64//#define flags___YESCRYPT_MODE_MASK (flags & YESCRYPT_MODE_MASK)
65// ^^^^ forcing the above since the code already requires (checks for) this
66// 50 bytes
67#define YCTX_param_N yctx->param.N
68// -100 bytes (negative!!!)
69#define YCTX_param_r yctx->param.r
70// 400 bytes
71//#define YCTX_param_p yctx->param.p
72// 130 bytes
73//#define YCTX_param_t yctx->param.t
74// 2 bytes
75//#define YCTX_param_g yctx->param.g
76// 1 bytes
77// ^^^^ this looks wrong, compiler should be able to constant-propagate the fact that NROM code is dead
78//#define YCTX_param_NROM yctx->param.NROM
79
80#ifndef YCTX_param_flags
81#define YCTX_param_flags (YESCRYPT_RW | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
82#endif
83#ifndef flags___YESCRYPT_RW
84#define flags___YESCRYPT_RW ((void)flags, YESCRYPT_RW)
85#endif
86#ifndef flags___YESCRYPT_MODE_MASK
87#define flags___YESCRYPT_MODE_MASK ((void)flags, YESCRYPT_RW)
88#endif
89// standard ("j9T") values:
90#ifndef YCTX_param_N
91#define YCTX_param_N 4096
92#endif
93#ifndef YCTX_param_r
94#define YCTX_param_r 32
95#endif
96#ifndef YCTX_param_p
97#define YCTX_param_p 1
98#endif
99#ifndef YCTX_param_t
100#define YCTX_param_t 0
101#endif
102#ifndef YCTX_param_g
103#define YCTX_param_g 0
104#endif
105#ifndef YCTX_param_NROM
106#define YCTX_param_NROM 0
107#endif
108
109// "Faster/smaller code" knobs:
110// -941 bytes:
111#define KDF_UNROLL_COPY 0
112// -5324 bytes if 0:
113#define KDF_UNROLL_PWXFORM_ROUND 0
114// -4864 bytes if 0:
115#define KDF_UNROLL_PWXFORM 0
116// if both this ^^^^^^^^^^ and PWXFORM_ROUND set to 0: -7666 bytes
117// -464 bytes:
118#define KDF_UNROLL_SALSA20 0
119
120/**
121 * Type and possible values for the flags argument of yescrypt_kdf(),
122 * yescrypt_encode_params_r(), yescrypt_encode_params(). Most of these may be
123 * OR'ed together, except that YESCRYPT_WORM stands on its own.
124 * Please refer to the description of yescrypt_kdf() below for the meaning of
125 * these flags.
126 */
127/* yescrypt flags:
128 * bits pos: 7654321076543210
129 * ss r w
130 * sbox gg y
131 */
132/* Public */
133#define YESCRYPT_WORM 1
134#define YESCRYPT_RW 0x002
135#define YESCRYPT_ROUNDS_3 0x000 //r=0
136#define YESCRYPT_ROUNDS_6 0x004 //r=1
137#define YESCRYPT_GATHER_1 0x000 //gg=00
138#define YESCRYPT_GATHER_2 0x008 //gg=01
139#define YESCRYPT_GATHER_4 0x010 //gg=10
140#define YESCRYPT_GATHER_8 0x018 //gg=11
141#define YESCRYPT_SIMPLE_1 0x000 //ss=00
142#define YESCRYPT_SIMPLE_2 0x020 //ss=01
143#define YESCRYPT_SIMPLE_4 0x040 //ss=10
144#define YESCRYPT_SIMPLE_8 0x060 //ss=11
145#define YESCRYPT_SBOX_6K 0x000 //sbox=0000
146#define YESCRYPT_SBOX_12K 0x080 //sbox=0001
147#define YESCRYPT_SBOX_24K 0x100 //sbox=0010
148#define YESCRYPT_SBOX_48K 0x180 //sbox=0011
149#define YESCRYPT_SBOX_96K 0x200 //sbox=0100
150#define YESCRYPT_SBOX_192K 0x280 //sbox=0101
151#define YESCRYPT_SBOX_384K 0x300 //sbox=0110
152#define YESCRYPT_SBOX_768K 0x380 //sbox=0111
153
154#ifdef YESCRYPT_INTERNAL
155/* Private */
156#define YESCRYPT_MODE_MASK 0x003
157#define YESCRYPT_RW_FLAVOR_MASK 0x3fc
158#define YESCRYPT_ALLOC_ONLY 0x08000000
159#define YESCRYPT_PREHASH 0x10000000
160#endif
161
162#define YESCRYPT_RW_DEFAULTS \
163 (YESCRYPT_RW | \
164 YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | \
165 YESCRYPT_SBOX_12K)
166
167#define YESCRYPT_DEFAULTS YESCRYPT_RW_DEFAULTS
168
169#ifdef YESCRYPT_INTERNAL
170#define YESCRYPT_KNOWN_FLAGS \
171 (YESCRYPT_MODE_MASK | YESCRYPT_RW_FLAVOR_MASK | \
172 YESCRYPT_ALLOC_ONLY | YESCRYPT_PREHASH)
173#endif
174
175/* How many chars base-64 encoded bytes require? */
176#define YESCRYPT_BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6)
177/* The /etc/passwd-style hash is "<prefix>$<hash><NUL>" */
178/*
179 * "$y$", up to 8 params of up to 6 chars each, '$', salt
180 * Alternatively, but that's smaller:
181 * "$7$", 3 params encoded as 1+5+5 chars, salt
182 */
183#define YESCRYPT_PREFIX_LEN (3 + 8 * 6 + 1 + YESCRYPT_BYTES2CHARS(32))
184
185#define YESCRYPT_HASH_SIZE 32
186#define YESCRYPT_HASH_LEN YESCRYPT_BYTES2CHARS(YESCRYPT_HASH_SIZE)
187
188/**
189 * Internal type used by the memory allocator. Please do not use it directly.
190 * Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since
191 * they might differ from each other in a future version.
192 */
193typedef struct {
194// void *base;
195 void *aligned;
196// size_t base_size;
197 size_t aligned_size;
198} yescrypt_region_t;
199
200/**
201 * yescrypt parameters combined into one struct. N, r, p are the same as in
202 * classic scrypt, except that the meaning of p changes when YESCRYPT_RW is
203 * set. flags, t, g, NROM are special to yescrypt.
204 */
205typedef struct {
206 uint32_t flags;
207 uint32_t r;
208 uint64_t N;
209#if !RESTRICTED_PARAMS
210 uint32_t p, t, g;
211 uint64_t NROM;
212#endif
213} yescrypt_params_t;
214
215typedef struct {
216 yescrypt_params_t param;
217
218 /* salt in binary form */
219 /* stored here to cut down on the amount of function paramaters */
220 unsigned char salt[64];
221 size_t saltlen;
222
223 /* used by the memory allocator */
224 //yescrypt_region_t shared[1];
225 yescrypt_region_t local[1];
226} yescrypt_ctx_t;
227
228/**
229 * yescrypt_r(shared, local, passwd, passwdlen, setting, key, buf, buflen):
230 * Compute and encode an scrypt or enhanced scrypt hash of passwd given the
231 * parameters and salt value encoded in setting. If shared is not NULL, a ROM
232 * is used and YESCRYPT_RW is required. Otherwise, whether to compute classic
233 * scrypt, YESCRYPT_WORM (a slight deviation from classic scrypt), or
234 * YESCRYPT_RW (time-memory tradeoff discouraging modification) is determined
235 * by the setting string. shared (if not NULL) and local must be initialized
236 * as described above for yescrypt_kdf(). buf must be large enough (as
237 * indicated by buflen) to hold the encoded hash string.
238 *
239 * Return the encoded hash string on success; or NULL on error.
240 *
241 * MT-safe as long as local and buf are local to the thread.
242 */
243extern char *yescrypt_r(
244 const uint8_t *passwd, size_t passwdlen,
245 const uint8_t *setting,
246 char *buf, size_t buflen
247);
diff --git a/libbb/yescrypt/y.c b/libbb/yescrypt/y.c
new file mode 100644
index 000000000..d5ab8903f
--- /dev/null
+++ b/libbb/yescrypt/y.c
@@ -0,0 +1,16 @@
1/*
2 * The compilation unit for yescrypt-related code.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += y.o
9
10#include "libbb.h"
11
12#define YESCRYPT_INTERNAL
13#include "alg-yescrypt.h"
14#include "alg-sha256.c"
15#include "alg-yescrypt-kdf.c"
16#include "alg-yescrypt-common.c"