diff options
Diffstat (limited to '')
63 files changed, 4825 insertions, 531 deletions
diff --git a/libbb/Config.src b/libbb/Config.src index 55e670dcd..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 | ||
| 40 | config 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 | |||
| 40 | config MD5_SMALL | 48 | config 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 | |||
| 67 | config SHA1_HWACCEL | 75 | config 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 | |||
| 74 | config SHA256_HWACCEL | 83 | config 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 | ||
| @@ -188,6 +198,16 @@ config FEATURE_EDITING_HISTORY | |||
| 188 | help | 198 | help |
| 189 | Specify command history size (0 - disable). | 199 | Specify command history size (0 - disable). |
| 190 | 200 | ||
| 201 | config 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 | |||
| 191 | config FEATURE_EDITING_SAVEHISTORY | 211 | config 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 | ||
| 11 | INSERT | 11 | INSERT |
| 12 | 12 | ||
| 13 | lib-y += alloc_affinity.o | ||
| 14 | lib-y += appletlib.o | 13 | lib-y += appletlib.o |
| 15 | lib-y += ask_confirmation.o | 14 | lib-y += ask_confirmation.o |
| 16 | lib-y += bb_askpass.o | ||
| 17 | lib-y += bb_bswap_64.o | 15 | lib-y += bb_bswap_64.o |
| 18 | lib-y += bb_do_delay.o | 16 | lib-y += bb_do_delay.o |
| 19 | lib-y += bb_pwd.o | 17 | lib-y += bb_pwd.o |
| 20 | lib-y += bb_qsort.o | 18 | lib-y += bb_qsort.o |
| 21 | #lib-y += bb_strtod.o | 19 | #lib-y += bb_strtod.o |
| 22 | lib-y += bb_strtonum.o | 20 | lib-y += bb_strtonum.o |
| 23 | lib-y += change_identity.o | ||
| 24 | lib-y += chomp.o | 21 | lib-y += chomp.o |
| 25 | lib-y += compare_string_array.o | 22 | lib-y += compare_string_array.o |
| 26 | lib-y += concat_path_file.o | 23 | lib-y += concat_path_file.o |
| @@ -30,32 +27,23 @@ lib-y += copy_file.o | |||
| 30 | lib-y += copyfd.o | 27 | lib-y += copyfd.o |
| 31 | lib-y += crc32.o | 28 | lib-y += crc32.o |
| 32 | lib-y += default_error_retval.o | 29 | lib-y += default_error_retval.o |
| 33 | lib-y += device_open.o | ||
| 34 | lib-y += dump.o | 30 | lib-y += dump.o |
| 35 | lib-y += executable.o | 31 | lib-y += executable.o |
| 36 | lib-y += fclose_nonstdin.o | 32 | lib-y += fclose_nonstdin.o |
| 37 | lib-y += fflush_stdout_and_exit.o | 33 | lib-y += fflush_stdout_and_exit.o |
| 38 | lib-y += fgets_str.o | 34 | lib-y += fgets_str.o |
| 39 | lib-y += find_pid_by_name.o | 35 | lib-y += find_pid_by_name.o |
| 40 | lib-y += find_root_device.o | ||
| 41 | lib-y += full_write.o | 36 | lib-y += full_write.o |
| 42 | lib-y += get_console.o | ||
| 43 | lib-y += get_last_path_component.o | 37 | lib-y += get_last_path_component.o |
| 44 | lib-y += get_line_from_file.o | 38 | lib-y += get_line_from_file.o |
| 45 | lib-y += getpty.o | 39 | lib-y += getopt32.o |
| 46 | lib-y += get_volsize.o | ||
| 47 | lib-y += herror_msg.o | 40 | lib-y += herror_msg.o |
| 48 | lib-y += human_readable.o | 41 | lib-y += human_readable.o |
| 49 | lib-y += inet_common.o | ||
| 50 | lib-y += inode_hash.o | ||
| 51 | lib-y += isdirectory.o | 42 | lib-y += isdirectory.o |
| 52 | lib-y += kernel_version.o | ||
| 53 | lib-y += last_char_is.o | 43 | lib-y += last_char_is.o |
| 54 | lib-y += lineedit.o lineedit_ptr_hack.o | 44 | lib-y += lineedit.o lineedit_ptr_hack.o |
| 55 | lib-y += llist.o | 45 | lib-y += llist.o |
| 56 | lib-y += login.o | ||
| 57 | lib-y += make_directory.o | 46 | lib-y += make_directory.o |
| 58 | lib-y += makedev.o | ||
| 59 | lib-y += hash_md5_sha.o | 47 | lib-y += hash_md5_sha.o |
| 60 | lib-y += hash_sha1_x86-64.o | 48 | lib-y += hash_sha1_x86-64.o |
| 61 | lib-y += hash_sha1_hwaccel_x86-64.o | 49 | lib-y += hash_sha1_hwaccel_x86-64.o |
| @@ -68,21 +56,18 @@ lib-y += messages.o | |||
| 68 | lib-y += mode_string.o | 56 | lib-y += mode_string.o |
| 69 | lib-y += parse_mode.o | 57 | lib-y += parse_mode.o |
| 70 | lib-y += perror_msg.o | 58 | lib-y += perror_msg.o |
| 71 | lib-y += perror_nomsg.o | ||
| 72 | lib-y += perror_nomsg_and_die.o | 59 | lib-y += perror_nomsg_and_die.o |
| 73 | lib-y += pidfile.o | ||
| 74 | lib-y += platform.o | 60 | lib-y += platform.o |
| 75 | lib-y += popcnt.o | 61 | lib-y += popcnt.o |
| 76 | lib-y += printable.o | 62 | lib-y += printable.o |
| 77 | lib-y += printable_string.o | 63 | lib-y += printable_string.o |
| 78 | lib-y += print_flags.o | ||
| 79 | lib-y += process_escape_sequence.o | 64 | lib-y += process_escape_sequence.o |
| 80 | lib-y += procps.o | 65 | lib-y += procps.o |
| 81 | lib-y += progress.o | 66 | lib-y += progress.o |
| 82 | lib-y += ptr_to_globals.o | 67 | lib-y += ptr_to_globals.o |
| 83 | lib-y += read.o | 68 | lib-y += read.o |
| 84 | lib-y += read_printf.o | ||
| 85 | lib-y += read_key.o | 69 | lib-y += read_key.o |
| 70 | lib-y += read_printf.o | ||
| 86 | lib-y += recursive_action.o | 71 | lib-y += recursive_action.o |
| 87 | lib-y += remove_file.o | 72 | lib-y += remove_file.o |
| 88 | lib-y += run_shell.o | 73 | lib-y += run_shell.o |
| @@ -91,12 +76,9 @@ lib-y += safe_poll.o | |||
| 91 | lib-y += safe_strncpy.o | 76 | lib-y += safe_strncpy.o |
| 92 | lib-y += safe_write.o | 77 | lib-y += safe_write.o |
| 93 | lib-y += securetty.o | 78 | lib-y += securetty.o |
| 94 | lib-y += setup_environment.o | ||
| 95 | lib-y += signals.o | ||
| 96 | lib-y += simplify_path.o | 79 | lib-y += simplify_path.o |
| 97 | lib-y += single_argv.o | 80 | lib-y += single_argv.o |
| 98 | lib-y += skip_whitespace.o | 81 | lib-y += skip_whitespace.o |
| 99 | lib-y += speed_table.o | ||
| 100 | lib-y += str_tolower.o | 82 | lib-y += str_tolower.o |
| 101 | lib-y += strrstr.o | 83 | lib-y += strrstr.o |
| 102 | lib-y += sysconf.o | 84 | lib-y += sysconf.o |
| @@ -109,17 +91,39 @@ lib-y += vfork_daemon_rexec.o | |||
| 109 | lib-y += warn_ignoring_args.o | 91 | lib-y += warn_ignoring_args.o |
| 110 | lib-y += wfopen.o | 92 | lib-y += wfopen.o |
| 111 | lib-y += wfopen_input.o | 93 | lib-y += wfopen_input.o |
| 112 | lib-y += write.o | ||
| 113 | lib-y += xatonum.o | 94 | lib-y += xatonum.o |
| 114 | lib-y += xconnect.o | 95 | lib-y += xconnect.o |
| 115 | lib-y += xfuncs.o | 96 | lib-y += xfuncs.o |
| 116 | lib-y += xfuncs_printf.o | 97 | lib-y += xfuncs_printf.o |
| 117 | lib-y += xfunc_die.o | 98 | lib-y += xfunc_die.o |
| 118 | lib-y += xgetcwd.o | 99 | lib-y += xgetcwd.o |
| 119 | lib-y += xgethostbyname.o | ||
| 120 | lib-y += xreadlink.o | 100 | lib-y += xreadlink.o |
| 121 | lib-y += xrealloc_vector.o | 101 | lib-y += xrealloc_vector.o |
| 122 | 102 | ||
| 103 | lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o | ||
| 104 | lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o | ||
| 105 | lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o | ||
| 106 | lib-$(CONFIG_PLATFORM_POSIX) += device_open.o | ||
| 107 | lib-$(CONFIG_PLATFORM_POSIX) += find_root_device.o | ||
| 108 | lib-$(CONFIG_PLATFORM_POSIX) += get_console.o | ||
| 109 | lib-$(CONFIG_PLATFORM_POSIX) += getpty.o | ||
| 110 | lib-$(CONFIG_PLATFORM_POSIX) += get_volsize.o | ||
| 111 | lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o | ||
| 112 | lib-$(CONFIG_PLATFORM_POSIX) += inode_hash.o | ||
| 113 | lib-$(CONFIG_FEATURE_EXTRA_FILE_DATA) += inode_hash.o | ||
| 114 | lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o | ||
| 115 | lib-$(CONFIG_PLATFORM_POSIX) += login.o | ||
| 116 | lib-$(CONFIG_PLATFORM_POSIX) += makedev.o | ||
| 117 | lib-$(CONFIG_PLATFORM_POSIX) += perror_nomsg.o | ||
| 118 | lib-$(CONFIG_PLATFORM_POSIX) += pidfile.o | ||
| 119 | lib-$(CONFIG_PLATFORM_POSIX) += print_flags.o | ||
| 120 | lib-$(CONFIG_PLATFORM_POSIX) += setup_environment.o | ||
| 121 | lib-$(CONFIG_PLATFORM_POSIX) += signals.o | ||
| 122 | lib-$(CONFIG_PLATFORM_POSIX) += speed_table.o | ||
| 123 | lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o | ||
| 124 | lib-$(CONFIG_PLATFORM_POSIX) += write.o | ||
| 125 | lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o | ||
| 126 | |||
| 123 | lib-$(CONFIG_MOUNT) += match_fstype.o | 127 | lib-$(CONFIG_MOUNT) += match_fstype.o |
| 124 | lib-$(CONFIG_UMOUNT) += match_fstype.o | 128 | lib-$(CONFIG_UMOUNT) += match_fstype.o |
| 125 | 129 | ||
| @@ -132,7 +136,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o | |||
| 132 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o | 136 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o |
| 133 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o | 137 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o |
| 134 | 138 | ||
| 135 | lib-$(CONFIG_NC) += udp_io.o | 139 | lib-$(CONFIG_NC_110_COMPAT) += udp_io.o |
| 136 | lib-$(CONFIG_NETCAT) += udp_io.o | 140 | lib-$(CONFIG_NETCAT) += udp_io.o |
| 137 | lib-$(CONFIG_DNSD) += udp_io.o | 141 | lib-$(CONFIG_DNSD) += udp_io.o |
| 138 | lib-$(CONFIG_NTPD) += udp_io.o | 142 | lib-$(CONFIG_NTPD) += udp_io.o |
| @@ -171,6 +175,7 @@ lib-$(CONFIG_MKE2FS) += find_mount_point.o | |||
| 171 | lib-$(CONFIG_MKFS_REISER) += find_mount_point.o | 175 | lib-$(CONFIG_MKFS_REISER) += find_mount_point.o |
| 172 | lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o | 176 | lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o |
| 173 | lib-$(CONFIG_MOUNT) += find_mount_point.o | 177 | lib-$(CONFIG_MOUNT) += find_mount_point.o |
| 178 | lib-$(CONFIG_STAT) += find_mount_point.o | ||
| 174 | 179 | ||
| 175 | lib-$(CONFIG_HWCLOCK) += rtc.o | 180 | lib-$(CONFIG_HWCLOCK) += rtc.o |
| 176 | lib-$(CONFIG_RTCWAKE) += rtc.o | 181 | lib-$(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" |
| 66 | static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; | 76 | static 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 | ||
| 105 | static 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 | ||
| 94 | unsigned FAST_FUNC string_array_len(char **argv) | 110 | unsigned 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 | ||
| 113 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; | 129 | static 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 | ||
| 202 | static int find_applet_by_name_internal(const char *name) | ||
| 203 | #else | ||
| 179 | int FAST_FUNC find_applet_by_name(const char *name) | 204 | int 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 | ||
| 272 | int 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 | |||
| 278 | int 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 | ||
| 285 | static 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 | |||
| 296 | static 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 | |||
| 335 | int 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 | ||
| 245 | void lbb_prepare(const char *applet | 348 | void 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 |
| 292 | bool re_execed; | 395 | bool re_execed; |
| 293 | #endif | 396 | #endif |
| 397 | #if ENABLE_PLATFORM_MINGW32 | ||
| 398 | static int interp = 0; | ||
| 399 | char bb_comm[COMM_LEN]; | ||
| 400 | char bb_command_line[128]; | ||
| 401 | |||
| 402 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 403 | void 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 | ||
| 955 | void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) | 1192 | void 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 | ||
| 13 | gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) | 14 | gid_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 | ||
| 49 | uid_t FAST_FUNC get_cached_euid(uid_t *euid) | 51 | uid_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. */ |
| 64 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) | 71 | int 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 | |||
| 12 | void 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 | |||
| 30 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) | ||
| 31 | { | ||
| 32 | xorbuf_3(dst, dst, src, count); | ||
| 33 | } | ||
| 34 | |||
| 35 | void 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 | |||
| 82 | void 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 | ||
| 119 | void 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/c_escape.c b/libbb/c_escape.c new file mode 100644 index 000000000..6c109f2e0 --- /dev/null +++ b/libbb/c_escape.c | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* vi: set sw=4 ts=4: */ | ||
| 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 | */ | ||
| 7 | //kbuild:lib-y += c_escape.o | ||
| 8 | |||
| 9 | #include "libbb.h" | ||
| 10 | |||
| 11 | const char c_escape_conv_str00[] ALIGN1 = | ||
| 12 | "\\""0""\0" // [0]:00 | ||
| 13 | "\\""a""\0" // [1]:07 | ||
| 14 | "\\""b""\0" // [2]:08 | ||
| 15 | "\\""t""\0" // [3]:09 | ||
| 16 | "\\""n""\0" // [4]:0a | ||
| 17 | "\\""v""\0" // [5]:0b | ||
| 18 | "\\""f""\0" // [6]:0c | ||
| 19 | "\\""r" // [7]:0d | ||
| 20 | ; | ||
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 | ||
| 31 | char* 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 | ||
| 35 | char* FAST_FUNC is_suffixed_with(const char *string, const char *key) | 49 | char* 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 | ||
| 64 | static 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 | |||
| 80 | char* FAST_FUNC is_suffixed_with(const char *string, const char *key) | ||
| 81 | { | ||
| 82 | return is_suffixed(string, key, strcmp); | ||
| 83 | } | ||
| 84 | |||
| 85 | char* 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..96fcd4a1d 100644 --- a/libbb/concat_path_file.c +++ b/libbb/concat_path_file.c | |||
| @@ -17,12 +17,93 @@ | |||
| 17 | 17 | ||
| 18 | char* FAST_FUNC concat_path_file(const char *path, const char *filename) | 18 | char* FAST_FUNC concat_path_file(const char *path, const char *filename) |
| 19 | { | 19 | { |
| 20 | #if 0 | ||
| 20 | char *lc; | 21 | char *lc; |
| 21 | 22 | ||
| 22 | if (!path) | 23 | if (!path) |
| 23 | path = ""; | 24 | path = ""; |
| 25 | #if ENABLE_PLATFORM_MINGW32 | ||
| 26 | lc = last_char_is_dir_sep(path); | ||
| 27 | while (is_dir_sep(*filename)) | ||
| 28 | filename++; | ||
| 29 | #else | ||
| 24 | lc = last_char_is(path, '/'); | 30 | lc = last_char_is(path, '/'); |
| 25 | while (*filename == '/') | 31 | while (*filename == '/') |
| 26 | filename++; | 32 | filename++; |
| 33 | #endif | ||
| 27 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); | 34 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); |
| 35 | #else | ||
| 36 | /* ^^^^^^^^^^^ timing of xasprintf-based code above: | ||
| 37 | * real 7.074s | ||
| 38 | * user 0.156s <<< | ||
| 39 | * sys 6.394s | ||
| 40 | * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though) | ||
| 41 | * real 6.989s | ||
| 42 | * user 0.055s <<< 3 times less CPU used | ||
| 43 | * sys 6.450s | ||
| 44 | * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes): | ||
| 45 | */ | ||
| 46 | char *buf, *p; | ||
| 47 | size_t n1, n2, n3; | ||
| 48 | |||
| 49 | while (*filename == '/') | ||
| 50 | filename++; | ||
| 51 | |||
| 52 | if (!path || !path[0]) | ||
| 53 | return xstrdup(filename); | ||
| 54 | |||
| 55 | n1 = strlen(path); | ||
| 56 | n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */ | ||
| 57 | n3 = strlen(filename) + 1; | ||
| 58 | |||
| 59 | buf = xmalloc(n1 + n2 + n3); | ||
| 60 | p = mempcpy(buf, path, n1); | ||
| 61 | if (n2) | ||
| 62 | *p++ = '/'; | ||
| 63 | memcpy(p, filename, n3); | ||
| 64 | return buf; | ||
| 65 | #endif | ||
| 28 | } | 66 | } |
| 67 | |||
| 68 | /* If second component comes from struct dirent, | ||
| 69 | * it's possible to eliminate one strlen() by using name length | ||
| 70 | * provided by kernel in struct dirent. See below. | ||
| 71 | * However, the win seems to be insignificant. | ||
| 72 | */ | ||
| 73 | |||
| 74 | #if 0 | ||
| 75 | |||
| 76 | /* Extract d_namlen from struct dirent */ | ||
| 77 | static size_t get_d_namlen(const struct dirent *de) | ||
| 78 | { | ||
| 79 | #if defined(_DIRENT_HAVE_D_NAMLEN) | ||
| 80 | return de->d_namlen; | ||
| 81 | #elif defined(_DIRENT_HAVE_D_RECLEN) | ||
| 82 | const size_t prefix_sz = offsetof(struct dirent, d_name); | ||
| 83 | return de->d_reclen - prefix_sz; | ||
| 84 | #else | ||
| 85 | return strlen(de->d_name); | ||
| 86 | #endif | ||
| 87 | } | ||
| 88 | |||
| 89 | char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de) | ||
| 90 | { | ||
| 91 | char *buf, *p; | ||
| 92 | size_t n1, n2, n3; | ||
| 93 | |||
| 94 | if (!path || !path[0]) | ||
| 95 | return xstrdup(de->d_name); | ||
| 96 | |||
| 97 | n1 = strlen(path); | ||
| 98 | n2 = (path[n1 - 1] != '/'); | ||
| 99 | n3 = get_d_namlen(de) + 1; | ||
| 100 | |||
| 101 | buf = xmalloc(n1 + n2 + n3); | ||
| 102 | p = mempcpy(buf, path, n1); | ||
| 103 | if (n2) | ||
| 104 | *p++ = '/'; | ||
| 105 | memcpy(p, de->d_name, n3); | ||
| 106 | return buf; | ||
| 107 | } | ||
| 108 | |||
| 109 | #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 ac5d47d9e..3dc53d55f 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; |
| @@ -478,37 +514,52 @@ static void bpad(PR *pr) | |||
| 478 | continue; | 514 | continue; |
| 479 | } | 515 | } |
| 480 | 516 | ||
| 481 | static const char conv_str[] ALIGN1 = | ||
| 482 | "\0" "\\""0""\0" | ||
| 483 | "\007""\\""a""\0" | ||
| 484 | "\b" "\\""b""\0" | ||
| 485 | "\f" "\\""f""\0" | ||
| 486 | "\n" "\\""n""\0" | ||
| 487 | "\r" "\\""r""\0" | ||
| 488 | "\t" "\\""t""\0" | ||
| 489 | "\v" "\\""v""\0" | ||
| 490 | ; | ||
| 491 | |||
| 492 | static void conv_c(PR *pr, unsigned char *p) | 517 | static void conv_c(PR *pr, unsigned char *p) |
| 493 | { | 518 | { |
| 494 | const char *str = conv_str; | 519 | const char *str; |
| 495 | 520 | unsigned char ch; | |
| 496 | do { | 521 | |
| 497 | if (*p == *str) { | 522 | ch = *p; |
| 498 | ++str; | 523 | if (ch == 0 || (ch -= 6, (signed char)ch > 0 && ch <= 7)) { |
| 499 | goto strpr; /* map e.g. '\n' to "\\n" */ | 524 | /* map chars 0,7..13 to "\0","\{a,b,t,n,v,f,r}" */ |
| 500 | } | 525 | str = c_escape_conv_str00 + 3 * ch; |
| 501 | str += 4; | 526 | goto strpr; |
| 502 | } while (*str); | 527 | } |
| 503 | 528 | ||
| 504 | if (isprint_asciionly(*p)) { | 529 | if (isprint_asciionly(*p)) { |
| 505 | *pr->cchar = 'c'; | 530 | *pr->cchar = 'c'; |
| 506 | printf(pr->fmt, *p); | 531 | printf(pr->fmt, *p); |
| 507 | } else { | 532 | } else { |
| 533 | #if defined(__i386__) || defined(__x86_64__) | ||
| 534 | /* Abuse partial register operations */ | ||
| 535 | uint32_t buf; | ||
| 536 | unsigned n = *p; | ||
| 537 | asm ( //00000000 00000000 00000000 aabbbccc | ||
| 538 | "\n shll $10,%%eax" //00000000 000000aa bbbccc00 00000000 | ||
| 539 | "\n shrw $5,%%ax" //00000000 000000aa 00000bbb ccc00000 | ||
| 540 | "\n shrb $5,%%al" //00000000 000000aa 00000bbb 00000ccc | ||
| 541 | "\n shll $8,%%eax" //000000aa 00000bbb 00000ccc 00000000 | ||
| 542 | "\n bswapl %%eax" //00000000 00000ccc 00000bbb 000000aa | ||
| 543 | "\n addl $0x303030,%%eax" | ||
| 544 | "\n" : "=a" (n) | ||
| 545 | : "0" (n) | ||
| 546 | ); | ||
| 547 | buf = n; | ||
| 548 | str = (void*)&buf; | ||
| 549 | #elif 1 | ||
| 508 | char buf[4]; | 550 | char buf[4]; |
| 509 | /* gcc-8.0.1 needs lots of casts to shut up */ | 551 | /* gcc-8.0.1 needs lots of casts to shut up */ |
| 510 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); | 552 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); |
| 511 | str = buf; | 553 | str = buf; |
| 554 | #else // use faster version? +20 bytes of code relative to sprintf() method | ||
| 555 | char buf[4]; | ||
| 556 | buf[3] = '\0'; | ||
| 557 | ch = *p; | ||
| 558 | buf[2] = '0' + (ch & 7); ch >>= 3; | ||
| 559 | buf[1] = '0' + (ch & 7); ch >>= 3; | ||
| 560 | buf[0] = '0' + ch; | ||
| 561 | str = buf; | ||
| 562 | #endif | ||
| 512 | strpr: | 563 | strpr: |
| 513 | *pr->cchar = 's'; | 564 | *pr->cchar = 's'; |
| 514 | printf(pr->fmt, str); | 565 | printf(pr->fmt, str); |
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 @@ | |||
| 15 | int FAST_FUNC file_is_executable(const char *name) | 15 | int 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 @@ | |||
| 19 | struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) | 22 | struct 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 | ||
| 40 | static int comm_match(procps_status_t *p, const char *procName) | 40 | static 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 | ||
| 11 | const char* FAST_FUNC bb_basename(const char *name) | 11 | const 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 | ||
| 27 | char * 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 | */ |
| 25 | char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path) | 47 | char* 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 | */ |
| 41 | char* FAST_FUNC bb_get_last_path_component_strip(char *path) | 73 | char* 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..9247588d9 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
| @@ -530,6 +530,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
| 530 | * "fake" short options, like this one: | 530 | * "fake" short options, like this one: |
| 531 | * wget $'-\203' "Test: test" http://kernel.org/ | 531 | * wget $'-\203' "Test: test" http://kernel.org/ |
| 532 | * (supposed to act as --header, but doesn't) */ | 532 | * (supposed to act as --header, but doesn't) */ |
| 533 | next_opt: | ||
| 533 | #if ENABLE_LONG_OPTS | 534 | #if ENABLE_LONG_OPTS |
| 534 | while ((c = getopt_long(argc, argv, applet_opts, | 535 | while ((c = getopt_long(argc, argv, applet_opts, |
| 535 | long_options, NULL)) != -1) { | 536 | long_options, NULL)) != -1) { |
| @@ -544,8 +545,16 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
| 544 | * but we construct long opts so that flag | 545 | * but we construct long opts so that flag |
| 545 | * is always NULL (see above) */ | 546 | * is always NULL (see above) */ |
| 546 | if (on_off->opt_char == '\0' /* && c != '\0' */) { | 547 | if (on_off->opt_char == '\0' /* && c != '\0' */) { |
| 547 | /* c is probably '?' - "bad option" */ | 548 | /* We reached the end of complementary[] and did not find -c */ |
| 548 | goto error; | 549 | if (c == '?') /* getopt says: "bad option, or option has no required argument" */ |
| 550 | goto error; | ||
| 551 | /* if there were options beyond 32 bits (example: ls), | ||
| 552 | * they got no complementary[] slot, and no result bit. | ||
| 553 | * IOW: they must be "accept but ignore" options. | ||
| 554 | * For them, we end up here. | ||
| 555 | */ | ||
| 556 | //bb_error_msg("ignored option '%c', skipping", c); | ||
| 557 | goto next_opt; | ||
| 549 | } | 558 | } |
| 550 | } | 559 | } |
| 551 | if (flags & on_off->incongruously) | 560 | if (flags & on_off->incongruously) |
| @@ -592,7 +601,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
| 592 | return (int32_t)-1; | 601 | return (int32_t)-1; |
| 593 | } | 602 | } |
| 594 | 603 | ||
| 595 | uint32_t FAST_FUNC | 604 | uint32_t |
| 596 | getopt32(char **argv, const char *applet_opts, ...) | 605 | getopt32(char **argv, const char *applet_opts, ...) |
| 597 | { | 606 | { |
| 598 | uint32_t opt; | 607 | uint32_t opt; |
| @@ -605,7 +614,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
| 605 | } | 614 | } |
| 606 | 615 | ||
| 607 | #if ENABLE_LONG_OPTS | 616 | #if ENABLE_LONG_OPTS |
| 608 | uint32_t FAST_FUNC | 617 | uint32_t |
| 609 | getopt32long(char **argv, const char *applet_opts, const char *longopts, ...) | 618 | getopt32long(char **argv, const char *applet_opts, const char *longopts, ...) |
| 610 | { | 619 | { |
| 611 | uint32_t opt; | 620 | 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 | ||
| 22 | void 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 | |||
| 60 | unsigned 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 | |||
| 68 | unsigned 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 | |||
| 78 | void 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 | ||
| 94 | void _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 | |||
| 114 | unsigned 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 | |||
| 124 | void 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 | |||
| 134 | void 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 | */ | ||
| 144 | unsigned 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..fd56d831b 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
| @@ -11,7 +11,93 @@ | |||
| 11 | #define STR1(s) #s | 11 | #define STR1(s) #s |
| 12 | #define STR(s) STR1(s) | 12 | #define STR(s) STR1(s) |
| 13 | 13 | ||
| 14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) | 14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_SHA384SUM || ENABLE_USE_BB_CRYPT_SHA) |
| 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_SHA384_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000051) | ||
| 25 | # define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061) | ||
| 26 | |||
| 27 | /* Initialize structure containing state of computation. | ||
| 28 | * (RFC 1321, 3.3: Step 3) | ||
| 29 | */ | ||
| 30 | |||
| 31 | static void generic_init(struct bcrypt_hash_ctx_t *ctx, BCRYPT_ALG_HANDLE alg_handle) { | ||
| 32 | DWORD hash_object_length = 0; | ||
| 33 | ULONG _unused; | ||
| 34 | NTSTATUS status; | ||
| 35 | |||
| 36 | status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0); | ||
| 37 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
| 38 | status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0); | ||
| 39 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
| 40 | |||
| 41 | |||
| 42 | ctx->hash_obj = xmalloc(hash_object_length); | ||
| 43 | |||
| 44 | status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj, hash_object_length, NULL, 0, 0); | ||
| 45 | mingw_die_if_error(status, "BCryptCreateHash"); | ||
| 46 | } | ||
| 47 | |||
| 48 | void FAST_FUNC md5_begin(md5_ctx_t *ctx) | ||
| 49 | { | ||
| 50 | generic_init(ctx, BCRYPT_MD5_ALG_HANDLE); | ||
| 51 | } | ||
| 52 | |||
| 53 | void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) | ||
| 54 | { | ||
| 55 | generic_init(ctx, BCRYPT_SHA1_ALG_HANDLE); | ||
| 56 | } | ||
| 57 | |||
| 58 | /* Initialize structure containing state of computation. | ||
| 59 | (FIPS 180-2:5.3.2) */ | ||
| 60 | void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | ||
| 61 | { | ||
| 62 | generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE); | ||
| 63 | } | ||
| 64 | |||
| 65 | #if ENABLE_SHA384SUM | ||
| 66 | /* Initialize structure containing state of computation. | ||
| 67 | (FIPS 180-2:5.3.3) */ | ||
| 68 | void FAST_FUNC sha384_begin(sha384_ctx_t *ctx) | ||
| 69 | { | ||
| 70 | generic_init(ctx, BCRYPT_SHA384_ALG_HANDLE); | ||
| 71 | } | ||
| 72 | #endif /* ENABLE_SHA384SUM */ | ||
| 73 | |||
| 74 | #if NEED_SHA512 | ||
| 75 | /* Initialize structure containing state of computation. | ||
| 76 | (FIPS 180-2:5.3.4) */ | ||
| 77 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | ||
| 78 | { | ||
| 79 | generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE); | ||
| 80 | } | ||
| 81 | #endif /* NEED_SHA512 */ | ||
| 82 | |||
| 83 | void FAST_FUNC generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) | ||
| 84 | { | ||
| 85 | /* | ||
| 86 | for perf, no error checking here | ||
| 87 | */ | ||
| 88 | /*NTSTATUS status = */ BCryptHashData(ctx->handle, (const PUCHAR)buffer, len, 0); | ||
| 89 | // mingw_die_if_error(status, "BCryptHashData"); | ||
| 90 | } | ||
| 91 | |||
| 92 | unsigned FAST_FUNC generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) | ||
| 93 | { | ||
| 94 | NTSTATUS status = BCryptFinishHash(ctx->handle, resbuf, ctx->output_size, 0); | ||
| 95 | mingw_die_if_error(status, "BCryptFinishHash"); | ||
| 96 | BCryptDestroyHash(ctx->handle); | ||
| 97 | free(ctx->hash_obj); | ||
| 98 | return ctx->output_size; | ||
| 99 | } | ||
| 100 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
| 15 | 101 | ||
| 16 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL | 102 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL |
| 17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | 103 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
| @@ -80,6 +166,7 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n) | |||
| 80 | return (x << n) | (x >> (64 - n)); | 166 | return (x << n) | (x >> (64 - n)); |
| 81 | } | 167 | } |
| 82 | 168 | ||
| 169 | #if !ENABLE_FEATURE_USE_CNG_API | ||
| 83 | /* Process the remaining bytes in the buffer */ | 170 | /* Process the remaining bytes in the buffer */ |
| 84 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) | 171 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) |
| 85 | { | 172 | { |
| @@ -1032,7 +1119,7 @@ static const sha_K_int sha_K[] ALIGN8 = { | |||
| 1032 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), | 1119 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), |
| 1033 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), | 1120 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), |
| 1034 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), | 1121 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), |
| 1035 | #if NEED_SHA512 /* [64]+ are used for sha512 only */ | 1122 | #if NEED_SHA512 /* [64]+ are used for sha384 and sha512 only */ |
| 1036 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), | 1123 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), |
| 1037 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), | 1124 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), |
| 1038 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), | 1125 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), |
| @@ -1229,11 +1316,20 @@ static const uint32_t init512_lo[] ALIGN4 = { | |||
| 1229 | 0x137e2179, | 1316 | 0x137e2179, |
| 1230 | }; | 1317 | }; |
| 1231 | #endif /* NEED_SHA512 */ | 1318 | #endif /* NEED_SHA512 */ |
| 1232 | 1319 | #if ENABLE_SHA384SUM | |
| 1233 | // Note: SHA-384 is identical to SHA-512, except that initial hash values are | 1320 | static const uint64_t init384[] ALIGN8 = { |
| 1234 | // 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, | 1321 | 0, |
| 1235 | // 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, | 1322 | 0, |
| 1236 | // and the output is constructed by omitting last two 64-bit words of it. | 1323 | 0xcbbb9d5dc1059ed8, |
| 1324 | 0x629a292a367cd507, | ||
| 1325 | 0x9159015a3070dd17, | ||
| 1326 | 0x152fecd8f70e5939, | ||
| 1327 | 0x67332667ffc00b31, | ||
| 1328 | 0x8eb44a8768581511, | ||
| 1329 | 0xdb0c2e0d64f98fa7, | ||
| 1330 | 0x47b5481dbefa4fa4, | ||
| 1331 | }; | ||
| 1332 | #endif | ||
| 1237 | 1333 | ||
| 1238 | /* Initialize structure containing state of computation. | 1334 | /* Initialize structure containing state of computation. |
| 1239 | (FIPS 180-2:5.3.2) */ | 1335 | (FIPS 180-2:5.3.2) */ |
| @@ -1255,9 +1351,19 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | |||
| 1255 | #endif | 1351 | #endif |
| 1256 | } | 1352 | } |
| 1257 | 1353 | ||
| 1258 | #if NEED_SHA512 | 1354 | #if ENABLE_SHA384SUM |
| 1259 | /* Initialize structure containing state of computation. | 1355 | /* Initialize structure containing state of computation. |
| 1260 | (FIPS 180-2:5.3.3) */ | 1356 | (FIPS 180-2:5.3.3) */ |
| 1357 | void FAST_FUNC sha384_begin(sha512_ctx_t *ctx) | ||
| 1358 | { | ||
| 1359 | memcpy(&ctx->total64, init384, sizeof(init384)); | ||
| 1360 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ | ||
| 1361 | } | ||
| 1362 | #endif | ||
| 1363 | |||
| 1364 | #if NEED_SHA512 | ||
| 1365 | /* Initialize structure containing state of computation. | ||
| 1366 | (FIPS 180-2:5.3.4) */ | ||
| 1261 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | 1367 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) |
| 1262 | { | 1368 | { |
| 1263 | int i; | 1369 | int i; |
| @@ -1332,7 +1438,7 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
| 1332 | } | 1438 | } |
| 1333 | 1439 | ||
| 1334 | #if NEED_SHA512 | 1440 | #if NEED_SHA512 |
| 1335 | unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | 1441 | static unsigned FAST_FUNC sha512384_end(sha512_ctx_t *ctx, void *resbuf, unsigned outsize) |
| 1336 | { | 1442 | { |
| 1337 | unsigned bufpos = ctx->total64[0] & 127; | 1443 | unsigned bufpos = ctx->total64[0] & 127; |
| 1338 | 1444 | ||
| @@ -1363,11 +1469,22 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | |||
| 1363 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) | 1469 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) |
| 1364 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); | 1470 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); |
| 1365 | } | 1471 | } |
| 1366 | memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); | 1472 | memcpy(resbuf, ctx->hash, outsize); |
| 1367 | return sizeof(ctx->hash); | 1473 | return outsize; |
| 1474 | } | ||
| 1475 | unsigned FAST_FUNC sha512_end(sha384_ctx_t *ctx, void *resbuf) | ||
| 1476 | { | ||
| 1477 | return sha512384_end(ctx, resbuf, SHA512_OUTSIZE); | ||
| 1368 | } | 1478 | } |
| 1369 | #endif /* NEED_SHA512 */ | 1479 | #endif /* NEED_SHA512 */ |
| 1370 | 1480 | ||
| 1481 | #if ENABLE_SHA384SUM | ||
| 1482 | unsigned FAST_FUNC sha384_end(sha384_ctx_t *ctx, void *resbuf) | ||
| 1483 | { | ||
| 1484 | return sha512384_end(ctx, resbuf, SHA384_OUTSIZE); | ||
| 1485 | } | ||
| 1486 | #endif | ||
| 1487 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
| 1371 | 1488 | ||
| 1372 | /* | 1489 | /* |
| 1373 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, | 1490 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, |
| @@ -1904,6 +2021,8 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) | |||
| 1904 | 2021 | ||
| 1905 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | 2022 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) |
| 1906 | { | 2023 | { |
| 2024 | unsigned hash_len; | ||
| 2025 | |||
| 1907 | /* Padding */ | 2026 | /* Padding */ |
| 1908 | uint8_t *buf = (uint8_t*)ctx->state; | 2027 | uint8_t *buf = (uint8_t*)ctx->state; |
| 1909 | /* | 2028 | /* |
| @@ -1926,6 +2045,7 @@ unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | |||
| 1926 | sha3_process_block72(ctx->state); | 2045 | sha3_process_block72(ctx->state); |
| 1927 | 2046 | ||
| 1928 | /* Output */ | 2047 | /* Output */ |
| 1929 | memcpy(resbuf, ctx->state, 64); | 2048 | hash_len = (1600/8 - ctx->input_block_bytes) / 2; |
| 1930 | return 64; | 2049 | memcpy(resbuf, ctx->state, hash_len); |
| 2050 | return hash_len; | ||
| 1931 | } | 2051 | } |
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 | |||
| 12 | void FAST_FUNC | ||
| 13 | sha256_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 |
| 47 | sha256_process_block64_shaNI: | 47 | sha256_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 |
| 50 | sha256_process_block64_shaNI: | 50 | sha256_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 | ||
| 11 | void FAST_FUNC bb_herror_msg(const char *s, ...) | 11 | void 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 | ||
| 20 | void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) | 20 | void 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 | ||
| 22 | char* 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 43d1da35c..77207a427 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 |
| 417 | static void put_cur_glyph_and_inc_cursor(void) | 423 | static void put_cur_glyph_and_inc_cursor(void) |
| 418 | { | 424 | { |
| 419 | CHAR_T c = command_ps[cursor]; | 425 | CHAR_T c = command_ps[cursor]; |
| @@ -476,6 +482,42 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
| 476 | } | 482 | } |
| 477 | } | 483 | } |
| 478 | 484 | ||
| 485 | #if ENABLE_PLATFORM_MINGW32 | ||
| 486 | static 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) */ |
| 480 | static void put_till_end_and_adv_cursor(void) | 522 | static 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) | |||
| 688 | static void input_forward(void) | 732 | static 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 | ||
| 712 | static void add_match(char *matched) | 772 | #if !ENABLE_PLATFORM_MINGW32 |
| 773 | # define add_match(m, s) add_match(m) | ||
| 774 | #endif | ||
| 775 | |||
| 776 | static 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 | ||
| 814 | static 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 | */ |
| 736 | static char *username_path_completion(char *ud) | 827 | static 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 | ||
| 786 | enum { | 883 | enum { |
| @@ -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 | } |
| @@ -1213,6 +1345,25 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1213 | size_t len_found; | 1345 | size_t len_found; |
| 1214 | /* Length of string used for matching */ | 1346 | /* Length of string used for matching */ |
| 1215 | 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 | ||
| 1216 | int find_type; | 1367 | int find_type; |
| 1217 | # if ENABLE_UNICODE_SUPPORT | 1368 | # if ENABLE_UNICODE_SUPPORT |
| 1218 | /* cursor pos in command converted to multibyte form */ | 1369 | /* cursor pos in command converted to multibyte form */ |
| @@ -1260,7 +1411,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1260 | /* Free up any memory already allocated */ | 1411 | /* Free up any memory already allocated */ |
| 1261 | free_tab_completion_data(); | 1412 | free_tab_completion_data(); |
| 1262 | 1413 | ||
| 1263 | # if ENABLE_FEATURE_USERNAME_COMPLETION | 1414 | # if ENABLE_FEATURE_USERNAME_COMPLETION && !ENABLE_PLATFORM_MINGW32 |
| 1264 | /* 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, |
| 1265 | * then try completing this word as a username. */ | 1416 | * then try completing this word as a username. */ |
| 1266 | if (state->flags & USERNAME_COMPLETION) | 1417 | if (state->flags & USERNAME_COMPLETION) |
| @@ -1277,6 +1428,9 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1277 | { | 1428 | { |
| 1278 | const char *e = match_buf + strlen(match_buf); | 1429 | const char *e = match_buf + strlen(match_buf); |
| 1279 | 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 | ||
| 1280 | while (s < e) | 1434 | while (s < e) |
| 1281 | if (is_special_char(*s++)) | 1435 | if (is_special_char(*s++)) |
| 1282 | match_pfx_len++; | 1436 | match_pfx_len++; |
| @@ -1307,10 +1461,29 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1307 | if (!matches) | 1461 | if (!matches) |
| 1308 | goto ret; /* no matches at all */ | 1462 | goto ret; /* no matches at all */ |
| 1309 | /* Find common prefix */ | 1463 | /* Find common prefix */ |
| 1310 | 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]); | ||
| 1311 | for (cp = chosen_match; *cp; cp++) { | 1476 | for (cp = chosen_match; *cp; cp++) { |
| 1312 | unsigned n; | 1477 | unsigned n; |
| 1313 | 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 | ||
| 1314 | if (matches[n][cp - chosen_match] != *cp) { | 1487 | if (matches[n][cp - chosen_match] != *cp) { |
| 1315 | goto stop; | 1488 | goto stop; |
| 1316 | } | 1489 | } |
| @@ -1347,7 +1520,21 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1347 | /* save tail */ | 1520 | /* save tail */ |
| 1348 | strcpy(match_buf, &command_ps[cursor]); | 1521 | strcpy(match_buf, &command_ps[cursor]); |
| 1349 | /* 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 | ||
| 1350 | 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 | ||
| 1351 | command_len = strlen(command_ps); | 1538 | command_len = strlen(command_ps); |
| 1352 | /* new pos */ | 1539 | /* new pos */ |
| 1353 | pos = cursor + len_found - match_pfx_len; | 1540 | pos = cursor + len_found - match_pfx_len; |
| @@ -1383,7 +1570,6 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
| 1383 | free(chosen_match); | 1570 | free(chosen_match); |
| 1384 | free(match_buf); | 1571 | free(match_buf); |
| 1385 | } | 1572 | } |
| 1386 | |||
| 1387 | #endif /* FEATURE_TAB_COMPLETION */ | 1573 | #endif /* FEATURE_TAB_COMPLETION */ |
| 1388 | 1574 | ||
| 1389 | 1575 | ||
| @@ -1403,7 +1589,11 @@ line_input_t* FAST_FUNC new_line_input_t(int flags) | |||
| 1403 | 1589 | ||
| 1404 | unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) | 1590 | unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) |
| 1405 | { | 1591 | { |
| 1592 | # if ENABLE_PLATFORM_MINGW32 && DEFAULT_HISTORY > 0 && DEFAULT_HISTORY <= MAX_HISTORY | ||
| 1593 | int size = DEFAULT_HISTORY; | ||
| 1594 | # else | ||
| 1406 | int size = MAX_HISTORY; | 1595 | int size = MAX_HISTORY; |
| 1596 | # endif | ||
| 1407 | if (hp) { | 1597 | if (hp) { |
| 1408 | size = atoi(hp); | 1598 | size = atoi(hp); |
| 1409 | if (size < 0) | 1599 | if (size < 0) |
| @@ -1564,7 +1754,7 @@ void FAST_FUNC save_history(line_input_t *st) | |||
| 1564 | FILE *fp; | 1754 | FILE *fp; |
| 1565 | 1755 | ||
| 1566 | /* bash compat: HISTFILE="" disables history saving */ | 1756 | /* bash compat: HISTFILE="" disables history saving */ |
| 1567 | if (!st || !st->hist_file || !state->hist_file[0]) | 1757 | if (!st || !st->hist_file || !st->hist_file[0]) |
| 1568 | return; | 1758 | return; |
| 1569 | if (st->cnt_history <= st->cnt_history_in_file) | 1759 | if (st->cnt_history <= st->cnt_history_in_file) |
| 1570 | return; /* no new entries were added */ | 1760 | return; /* no new entries were added */ |
| @@ -2066,7 +2256,11 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
| 2066 | char *after_home_user; | 2256 | char *after_home_user; |
| 2067 | 2257 | ||
| 2068 | /* /home/user[/something] -> ~[/something] */ | 2258 | /* /home/user[/something] -> ~[/something] */ |
| 2259 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 2069 | 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 | ||
| 2070 | if (after_home_user | 2264 | if (after_home_user |
| 2071 | && (*after_home_user == '/' || *after_home_user == '\0') | 2265 | && (*after_home_user == '/' || *after_home_user == '\0') |
| 2072 | ) { | 2266 | ) { |
| @@ -2496,7 +2690,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2496 | 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 |
| 2497 | | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ | 2691 | | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ |
| 2498 | ); | 2692 | ); |
| 2693 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 2499 | 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 | ||
| 2500 | /* Happens when e.g. stty -echo was run before. | 2698 | /* Happens when e.g. stty -echo was run before. |
| 2501 | * But if ICANON is not set, we don't come here. | 2699 | * But if ICANON is not set, we don't come here. |
| 2502 | * (example: interactive python ^Z-backgrounded, | 2700 | * (example: interactive python ^Z-backgrounded, |
| @@ -2506,8 +2704,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2506 | fflush_all(); | 2704 | fflush_all(); |
| 2507 | if (fgets(command, maxsize, stdin) == NULL) | 2705 | if (fgets(command, maxsize, stdin) == NULL) |
| 2508 | len = -1; /* EOF or error */ | 2706 | len = -1; /* EOF or error */ |
| 2509 | else | 2707 | else { |
| 2510 | len = strlen(command); | 2708 | len = strlen(command); |
| 2709 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2710 | len = remove_cr(command, len); | ||
| 2711 | #endif | ||
| 2712 | } | ||
| 2511 | DEINIT_S(); | 2713 | DEINIT_S(); |
| 2512 | return len; | 2714 | return len; |
| 2513 | } | 2715 | } |
| @@ -2589,6 +2791,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2589 | } | 2791 | } |
| 2590 | #endif | 2792 | #endif |
| 2591 | 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 | ||
| 2592 | 2799 | ||
| 2593 | #if ENABLE_FEATURE_REVERSE_SEARCH | 2800 | #if ENABLE_FEATURE_REVERSE_SEARCH |
| 2594 | again: | 2801 | again: |
| @@ -2650,6 +2857,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2650 | input_tab(&lastWasTab); | 2857 | input_tab(&lastWasTab); |
| 2651 | break; | 2858 | break; |
| 2652 | #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 | ||
| 2653 | case CTRL('K'): | 2871 | case CTRL('K'): |
| 2654 | /* Control-k -- clear to end of line */ | 2872 | /* Control-k -- clear to end of line */ |
| 2655 | command_ps[cursor] = BB_NUL; | 2873 | command_ps[cursor] = BB_NUL; |
| @@ -2904,6 +3122,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2904 | && ic_raw == initial_settings.c_cc[VINTR] | 3122 | && ic_raw == initial_settings.c_cc[VINTR] |
| 2905 | ) { | 3123 | ) { |
| 2906 | /* 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 | ||
| 2907 | command_len = 0; | 3129 | command_len = 0; |
| 2908 | break_out = -1; /* "do not append '\n'" */ | 3130 | break_out = -1; /* "do not append '\n'" */ |
| 2909 | 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 | ||
| 28 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; | 31 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; |
| 29 | 32 | ||
| 33 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 30 | const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; | 34 | const 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 | */ | ||
| 46 | const 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 | ||
| 31 | const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; | 53 | const 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 | ||
| 11 | void FAST_FUNC bb_perror_msg(const char *s, ...) | 11 | void 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 | ||
| 21 | void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) | 21 | void 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 index 47419f240..d3c005418 100644 --- a/libbb/poll_with_signals.c +++ b/libbb/poll_with_signals.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * | 6 | * |
| 7 | * Licensed under GPLv2, see file LICENSE in this source tree. | 7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
| 8 | */ | 8 | */ |
| 9 | //kbuild:lib-y += poll_with_signals.o | 9 | //kbuild:lib-$(CONFIG_PLATFORM_POSIX) += poll_with_signals.o |
| 10 | 10 | ||
| 11 | #include "libbb.h" | 11 | #include "libbb.h" |
| 12 | 12 | ||
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..c751100bc 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 | ||
| @@ -109,7 +110,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp) | |||
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 112 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
| 112 | static unsigned long long fast_strtoull_16(char **endptr) | 113 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr) |
| 113 | { | 114 | { |
| 114 | unsigned char c; | 115 | unsigned char c; |
| 115 | char *str = *endptr; | 116 | char *str = *endptr; |
| @@ -130,7 +131,7 @@ static unsigned long long fast_strtoull_16(char **endptr) | |||
| 130 | 131 | ||
| 131 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 132 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
| 132 | /* We cut a lot of corners here for speed */ | 133 | /* We cut a lot of corners here for speed */ |
| 133 | static unsigned long fast_strtoul_10(char **endptr) | 134 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr) |
| 134 | { | 135 | { |
| 135 | unsigned char c; | 136 | unsigned char c; |
| 136 | char *str = *endptr; | 137 | char *str = *endptr; |
| @@ -143,6 +144,24 @@ static unsigned long fast_strtoul_10(char **endptr) | |||
| 143 | *endptr = str + 1; /* We skip trailing space! */ | 144 | *endptr = str + 1; /* We skip trailing space! */ |
| 144 | return n; | 145 | return n; |
| 145 | } | 146 | } |
| 147 | # if LONG_MAX < LLONG_MAX | ||
| 148 | /* For VSZ, which can be very large */ | ||
| 149 | static unsigned long long fast_strtoull_10(char **endptr) | ||
| 150 | { | ||
| 151 | unsigned char c; | ||
| 152 | char *str = *endptr; | ||
| 153 | unsigned long long n = *str - '0'; | ||
| 154 | |||
| 155 | /* Need to stop on both ' ' and '\n' */ | ||
| 156 | while ((c = *++str) > ' ') | ||
| 157 | n = n*10 + (c - '0'); | ||
| 158 | |||
| 159 | *endptr = str + 1; /* We skip trailing space! */ | ||
| 160 | return n; | ||
| 161 | } | ||
| 162 | # else | ||
| 163 | # define fast_strtoull_10(endptr) fast_strtoul_10(endptr) | ||
| 164 | # endif | ||
| 146 | 165 | ||
| 147 | # if ENABLE_FEATURE_FAST_TOP | 166 | # if ENABLE_FEATURE_FAST_TOP |
| 148 | static long fast_strtol_10(char **endptr) | 167 | static long fast_strtol_10(char **endptr) |
| @@ -155,7 +174,7 @@ static long fast_strtol_10(char **endptr) | |||
| 155 | } | 174 | } |
| 156 | # endif | 175 | # endif |
| 157 | 176 | ||
| 158 | static char *skip_fields(char *str, int count) | 177 | char* FAST_FUNC skip_fields(char *str, int count) |
| 159 | { | 178 | { |
| 160 | do { | 179 | do { |
| 161 | while (*str++ != ' ') | 180 | while (*str++ != ' ') |
| @@ -166,35 +185,25 @@ static char *skip_fields(char *str, int count) | |||
| 166 | } | 185 | } |
| 167 | #endif | 186 | #endif |
| 168 | 187 | ||
| 169 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 188 | #if ENABLE_FEATURE_TOPMEM |
| 170 | static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) | 189 | static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp) |
| 171 | { | 190 | { |
| 172 | char *tp = is_prefixed_with(buf, prefix); | 191 | // There is A LOT of /proc/PID/smaps data on a big system. |
| 173 | if (tp) { | 192 | // Optimize this for speed, makes "top -m" faster. |
| 174 | tp = skip_whitespace(tp); | 193 | //TODO large speedup: |
| 175 | } | 194 | //read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster) |
| 176 | return tp; | 195 | //and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW) |
| 177 | } | ||
| 178 | 196 | ||
| 179 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
| 180 | void (*cb)(struct smaprec *, void *), void *data) | ||
| 181 | { | ||
| 182 | FILE *file; | 197 | FILE *file; |
| 183 | struct smaprec currec; | ||
| 184 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | 198 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; |
| 185 | char buf[PROCPS_BUFSIZE]; | 199 | char buf[PROCPS_BUFSIZE]; |
| 186 | #if !ENABLE_PMAP | ||
| 187 | void (*cb)(struct smaprec *, void *) = NULL; | ||
| 188 | void *data = NULL; | ||
| 189 | #endif | ||
| 190 | 200 | ||
| 191 | sprintf(filename, "/proc/%u/smaps", (int)pid); | 201 | sprintf(filename, "/proc/%u/smaps", (int)pid); |
| 192 | 202 | ||
| 193 | file = fopen_for_read(filename); | 203 | file = fopen_for_read(filename); |
| 194 | if (!file) | 204 | if (!file) |
| 195 | return 1; | 205 | return; |
| 196 | 206 | ||
| 197 | memset(&currec, 0, sizeof(currec)); | ||
| 198 | while (fgets(buf, PROCPS_BUFSIZE, file)) { | 207 | while (fgets(buf, PROCPS_BUFSIZE, file)) { |
| 199 | // Each mapping datum has this form: | 208 | // Each mapping datum has this form: |
| 200 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 209 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
| @@ -202,80 +211,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | |||
| 202 | // Rss: nnn kB | 211 | // Rss: nnn kB |
| 203 | // ..... | 212 | // ..... |
| 204 | 213 | ||
| 205 | char *tp, *p; | 214 | char *tp; |
| 206 | 215 | ||
| 216 | if (buf[0] == 'S' || buf[0] == 'P') { | ||
| 207 | #define SCAN(S, X) \ | 217 | #define SCAN(S, X) \ |
| 208 | if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ | 218 | if (memcmp(buf, S, sizeof(S)-1) == 0) { \ |
| 209 | total->X += currec.X = fast_strtoul_10(&tp); \ | 219 | tp = skip_whitespace(buf + sizeof(S)-1); \ |
| 210 | continue; \ | 220 | sp->X += fast_strtoul_10(&tp); \ |
| 211 | } | 221 | continue; \ |
| 212 | if (cb) { | 222 | } |
| 213 | SCAN("Pss:" , smap_pss ); | 223 | SCAN("Private_Dirty:", private_dirty) |
| 214 | SCAN("Swap:" , smap_swap ); | 224 | SCAN("Private_Clean:", private_clean) |
| 215 | } | 225 | SCAN("Shared_Dirty:" , shared_dirty ) |
| 216 | SCAN("Private_Dirty:", private_dirty); | 226 | SCAN("Shared_Clean:" , shared_clean ) |
| 217 | SCAN("Private_Clean:", private_clean); | ||
| 218 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
| 219 | SCAN("Shared_Clean:" , shared_clean ); | ||
| 220 | #undef SCAN | 227 | #undef SCAN |
| 228 | } | ||
| 221 | tp = strchr(buf, '-'); | 229 | tp = strchr(buf, '-'); |
| 222 | if (tp) { | 230 | if (tp) { |
| 223 | // We reached next mapping - the line of this form: | 231 | // We reached next mapping - the line of this form: |
| 224 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 232 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
| 225 | 233 | ||
| 226 | if (cb) { | 234 | char *rwx; |
| 227 | /* If we have a previous record, there's nothing more | 235 | unsigned long sz; |
| 228 | * for it, call the callback and clear currec | ||
| 229 | */ | ||
| 230 | if (currec.smap_size) | ||
| 231 | cb(&currec, data); | ||
| 232 | free(currec.smap_name); | ||
| 233 | } | ||
| 234 | memset(&currec, 0, sizeof(currec)); | ||
| 235 | 236 | ||
| 236 | *tp = ' '; | 237 | *tp = ' '; |
| 237 | tp = buf; | 238 | tp = buf; |
| 238 | currec.smap_start = fast_strtoull_16(&tp); | 239 | sz = fast_strtoull_16(&tp); // start |
| 239 | currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; | 240 | sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start |
| 240 | 241 | // tp -> "rw-s" string | |
| 241 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | 242 | rwx = tp; |
| 242 | |||
| 243 | // skipping "rw-s FILEOFS M:m INODE " | 243 | // skipping "rw-s FILEOFS M:m INODE " |
| 244 | tp = skip_whitespace(skip_fields(tp, 4)); | 244 | tp = skip_whitespace(skip_fields(tp, 4)); |
| 245 | // filter out /dev/something (something != zero) | 245 | // if not a device memory mapped... |
| 246 | if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { | 246 | if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something" |
| 247 | if (currec.smap_mode[1] == 'w') { | 247 | || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device) |
| 248 | currec.mapped_rw = currec.smap_size; | 248 | ) { |
| 249 | total->mapped_rw += currec.smap_size; | 249 | if (rwx[1] == 'w') |
| 250 | } else if (currec.smap_mode[1] == '-') { | 250 | sp->mapped_rw += sz; |
| 251 | currec.mapped_ro = currec.smap_size; | 251 | else if (rwx[0] == 'r' || rwx[2] == 'x') |
| 252 | total->mapped_ro += currec.smap_size; | 252 | sp->mapped_ro += sz; |
| 253 | } | 253 | // else: seen "---p" mappings (mmap guard gaps?), |
| 254 | // do NOT account these as VSZ, they aren't really | ||
| 254 | } | 255 | } |
| 255 | |||
| 256 | if (strcmp(tp, "[stack]\n") == 0) | 256 | if (strcmp(tp, "[stack]\n") == 0) |
| 257 | total->stack += currec.smap_size; | 257 | sp->stack += sz; |
| 258 | if (cb) { | ||
| 259 | p = skip_non_whitespace(tp); | ||
| 260 | if (p == tp) { | ||
| 261 | currec.smap_name = xstrdup(" [ anon ]"); | ||
| 262 | } else { | ||
| 263 | *p = '\0'; | ||
| 264 | currec.smap_name = xstrdup(tp); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | total->smap_size += currec.smap_size; | ||
| 268 | } | 258 | } |
| 269 | } | 259 | } |
| 270 | fclose(file); | 260 | fclose(file); |
| 271 | |||
| 272 | if (cb) { | ||
| 273 | if (currec.smap_size) | ||
| 274 | cb(&currec, data); | ||
| 275 | free(currec.smap_name); | ||
| 276 | } | ||
| 277 | |||
| 278 | return 0; | ||
| 279 | } | 261 | } |
| 280 | #endif | 262 | #endif |
| 281 | 263 | ||
| @@ -370,7 +352,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
| 370 | char *cp, *comm1; | 352 | char *cp, *comm1; |
| 371 | int tty; | 353 | int tty; |
| 372 | #if !ENABLE_FEATURE_FAST_TOP | 354 | #if !ENABLE_FEATURE_FAST_TOP |
| 373 | unsigned long vsz, rss; | 355 | unsigned long long vsz; |
| 356 | unsigned long rss; | ||
| 374 | #endif | 357 | #endif |
| 375 | /* see proc(5) for some details on this */ | 358 | /* see proc(5) for some details on this */ |
| 376 | strcpy(filename_tail, "stat"); | 359 | strcpy(filename_tail, "stat"); |
| @@ -396,7 +379,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
| 396 | "%ld " /* nice */ | 379 | "%ld " /* nice */ |
| 397 | "%*s %*s " /* timeout, it_real_value */ | 380 | "%*s %*s " /* timeout, it_real_value */ |
| 398 | "%lu " /* start_time */ | 381 | "%lu " /* start_time */ |
| 399 | "%lu " /* vsize */ | 382 | "%llu " /* vsize - can be very large */ |
| 400 | "%lu " /* rss */ | 383 | "%lu " /* rss */ |
| 401 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 384 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
| 402 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 385 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
| @@ -449,7 +432,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
| 449 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ | 432 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ |
| 450 | sp->start_time = fast_strtoul_10(&cp); | 433 | sp->start_time = fast_strtoul_10(&cp); |
| 451 | /* vsz is in bytes and we want kb */ | 434 | /* vsz is in bytes and we want kb */ |
| 452 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 435 | sp->vsz = fast_strtoull_10(&cp) >> 10; |
| 453 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 436 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
| 454 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 437 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
| 455 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 438 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
| @@ -483,7 +466,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
| 483 | 466 | ||
| 484 | #if ENABLE_FEATURE_TOPMEM | 467 | #if ENABLE_FEATURE_TOPMEM |
| 485 | if (flags & PSSCAN_SMAPS) | 468 | if (flags & PSSCAN_SMAPS) |
| 486 | procps_read_smaps(pid, &sp->smaps, NULL, NULL); | 469 | procps_read_smaps(pid, sp); |
| 487 | #endif /* TOPMEM */ | 470 | #endif /* TOPMEM */ |
| 488 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 471 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
| 489 | if (flags & PSSCAN_RUIDGID) { | 472 | if (flags & PSSCAN_RUIDGID) { |
| @@ -566,36 +549,45 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
| 566 | return sp; | 549 | return sp; |
| 567 | } | 550 | } |
| 568 | 551 | ||
| 569 | void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | 552 | int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) |
| 570 | { | 553 | { |
| 571 | int sz; | 554 | int sz; |
| 572 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; | 555 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; |
| 573 | 556 | ||
| 574 | sprintf(filename, "/proc/%u/cmdline", pid); | 557 | sprintf(filename, "/proc/%u/cmdline", pid); |
| 575 | sz = open_read_close(filename, buf, col - 1); | 558 | sz = open_read_close(filename, buf, col - 1); |
| 559 | if (sz < 0) | ||
| 560 | return sz; | ||
| 576 | if (sz > 0) { | 561 | if (sz > 0) { |
| 577 | const char *base; | 562 | const char *program_basename; |
| 578 | int comm_len; | 563 | int comm_len; |
| 579 | 564 | ||
| 580 | buf[sz] = '\0'; | 565 | buf[sz] = '\0'; |
| 581 | while (--sz >= 0 && buf[sz] == '\0') | 566 | while (--sz >= 0 && buf[sz] == '\0') |
| 582 | continue; | 567 | continue; |
| 583 | /* Prevent basename("process foo/bar") = "bar" */ | 568 | |
| 584 | strchrnul(buf, ' ')[0] = '\0'; | 569 | /* Find "program" in "[-][/PATH/TO/]program" */ |
| 585 | base = bb_basename(buf); /* before we replace argv0's NUL with space */ | 570 | strchrnul(buf, ' ')[0] = '\0'; /* prevent basename("program foo/bar") = "bar" */ |
| 571 | program_basename = bb_basename(buf[0] == '-' ? buf + 1 : buf); | ||
| 572 | /* ^^^ note: must do it *before* replacing argv0's NUL with space */ | ||
| 573 | |||
| 574 | /* Prevent stuff like this: | ||
| 575 | * echo 'sleep 999; exit' >`printf '\ec'`; sh ?c | ||
| 576 | * messing up top and ps output (or worse). | ||
| 577 | * This also replaces NULs with spaces, converting | ||
| 578 | * list of NUL-strings into one string. | ||
| 579 | */ | ||
| 586 | while (sz >= 0) { | 580 | while (sz >= 0) { |
| 587 | if ((unsigned char)(buf[sz]) < ' ') | 581 | if ((unsigned char)(buf[sz]) < ' ') |
| 588 | buf[sz] = ' '; | 582 | buf[sz] = ' '; |
| 589 | sz--; | 583 | sz--; |
| 590 | } | 584 | } |
| 591 | if (base[0] == '-') /* "-sh" (login shell)? */ | ||
| 592 | base++; | ||
| 593 | 585 | ||
| 594 | /* If comm differs from argv0, prepend "{comm} ". | 586 | /* If comm differs from argv0, prepend "{comm} ". |
| 595 | * It allows to see thread names set by prctl(PR_SET_NAME). | 587 | * It allows to see thread names set by prctl(PR_SET_NAME). |
| 596 | */ | 588 | */ |
| 597 | if (!comm) | 589 | if (!comm) |
| 598 | return; | 590 | return 0; |
| 599 | comm_len = strlen(comm); | 591 | comm_len = strlen(comm); |
| 600 | /* Why compare up to comm_len, not COMM_LEN-1? | 592 | /* Why compare up to comm_len, not COMM_LEN-1? |
| 601 | * Well, some processes rewrite argv, and use _spaces_ there | 593 | * Well, some processes rewrite argv, and use _spaces_ there |
| @@ -603,21 +595,24 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
| 603 | * I prefer to still treat argv0 "process foo bar" | 595 | * I prefer to still treat argv0 "process foo bar" |
| 604 | * as 'equal' to comm "process". | 596 | * as 'equal' to comm "process". |
| 605 | */ | 597 | */ |
| 606 | if (strncmp(base, comm, comm_len) != 0) { | 598 | if (strncmp(program_basename, comm, comm_len) != 0) { |
| 607 | comm_len += 3; | 599 | comm_len += 3; |
| 608 | if (col > comm_len) | 600 | if (col > comm_len) |
| 609 | memmove(buf + comm_len, buf, col - comm_len); | 601 | memmove(buf + comm_len, buf, col - comm_len); |
| 610 | snprintf(buf, col, "{%s}", comm); | 602 | snprintf(buf, col, "{%s}", comm); |
| 611 | if (col <= comm_len) | 603 | if (col <= comm_len) |
| 612 | return; | 604 | return 0; |
| 613 | buf[comm_len - 1] = ' '; | 605 | buf[comm_len - 1] = ' '; |
| 614 | buf[col - 1] = '\0'; | 606 | buf[col - 1] = '\0'; |
| 615 | } | 607 | } |
| 616 | } else { | 608 | } else { |
| 617 | snprintf(buf, col, "[%s]", comm ? comm : "?"); | 609 | snprintf(buf, col, "[%s]", comm ? comm : "?"); |
| 618 | } | 610 | } |
| 611 | return 0; | ||
| 619 | } | 612 | } |
| 620 | 613 | ||
| 614 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
| 615 | |||
| 621 | /* from kernel: | 616 | /* from kernel: |
| 622 | // pid comm S ppid pgid sid tty_nr tty_pgrp flg | 617 | // pid comm S ppid pgid sid tty_nr tty_pgrp flg |
| 623 | sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ | 618 | 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 */ | ||
| 11 | int 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 | */ | ||
| 38 | int 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 | |||
| 53 | char* FAST_FUNC | ||
| 54 | num2str64_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 | |||
| 63 | static void | ||
| 64 | num2str64_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 | |||
| 72 | int 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 | |||
| 20 | static 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 | |||
| 34 | int 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 | ||
| 55 | char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) | 18 | char* 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(¶ms, 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 | |||
| 81 | static char* | ||
| 82 | to64(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 */ |
| 110 | static char *my_crypt(const char *key, const char *salt) | 109 | static 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 | ||
| 189 | static 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 | |||
| 200 | static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; | 189 | static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; |
| 201 | 190 | ||
| 202 | 191 | ||
| 203 | static int | ||
| 204 | ascii_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 | ||
| 697 | static void | ||
| 698 | to64_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 | |||
| 712 | static char * | 674 | static char * |
| 713 | NOINLINE | 675 | NOINLINE |
| 714 | des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], | 676 | des_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) \ |
| 199 | do { \ | 198 | do { \ |
| 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 | |||
| 10 | static char * | ||
| 11 | yes_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 3df9769f7..2414105ee 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
| @@ -112,6 +112,11 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
| 112 | 0 | 112 | 0 |
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | #if ENABLE_PLATFORM_MINGW32 | ||
| 116 | if (!(terminal_mode(FALSE) & VT_INPUT)) | ||
| 117 | return windows_read_key(fd, buffer, timeout); | ||
| 118 | #endif | ||
| 119 | |||
| 115 | pfd->fd = fd; | 120 | pfd->fd = fd; |
| 116 | pfd->events = POLLIN; | 121 | pfd->events = POLLIN; |
| 117 | 122 | ||
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/replace.c b/libbb/replace.c index 6183d3e6f..bc26b04cc 100644 --- a/libbb/replace.c +++ b/libbb/replace.c | |||
| @@ -46,3 +46,17 @@ char* FAST_FUNC xmalloc_substitute_string(const char *src, int count, const char | |||
| 46 | //dbg_msg("subst9:'%s'", buf); | 46 | //dbg_msg("subst9:'%s'", buf); |
| 47 | return buf; | 47 | return buf; |
| 48 | } | 48 | } |
| 49 | |||
| 50 | #if 0 /* inlined in libbb.h */ | ||
| 51 | /* Returns strlen as a bonus */ | ||
| 52 | size_t FAST_FUNC replace_char(char *str, char from, char to) | ||
| 53 | { | ||
| 54 | char *p = str; | ||
| 55 | while (*p) { | ||
| 56 | if (*p == from) | ||
| 57 | *p = to; | ||
| 58 | p++; | ||
| 59 | } | ||
| 60 | return p - str; | ||
| 61 | } | ||
| 62 | #endif | ||
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... */ |
| 22 | int FAST_FUNC sigaction_set(int signum, const struct sigaction *act) | 23 | int 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 | ||
| 44 | void FAST_FUNC bb_signals(int sigs, void (*f)(int)) | 46 | void 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 | ||
| 33 | static const char signals[][7] ALIGN1 = { | 42 | static 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) | |||
| 69 | void FAST_FUNC reinit_unicode(const char *LANG) | 69 | void 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 |
| 275 | struct interval { | 283 | struct 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 |
| 702 | int FAST_FUNC unicode_bidi_isrtl(wint_t wc) | 715 | int 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 | ||
| 159 | void FAST_FUNC bb_error_msg_and_die(const char *s, ...) | 159 | void 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 | ||
| 169 | void FAST_FUNC bb_error_msg(const char *s, ...) | 169 | void 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 | ||
| 186 | void FAST_FUNC bb_info_msg(const char *s, ...) | 186 | void 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. */ |
| 176 | pid_t FAST_FUNC spawn(char **argv) | 177 | pid_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. */ |
| 217 | pid_t FAST_FUNC xspawn(char **argv) | 219 | pid_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 |
| 252 | void FAST_FUNC re_exec(char **argv) | 257 | void 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 | */ | ||
| 8 | int 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 | ||
| 74 | static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen)) | 75 | static 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 | ||
| 103 | void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) | 105 | void 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 | ||
| 26 | int FAST_FUNC ndelay_on(int fd) | 27 | int 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 | ||
| 49 | char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) | 51 | char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) |
| 50 | { | 52 | { |
| @@ -219,7 +221,12 @@ off_t FAST_FUNC fdlength(int fd) | |||
| 219 | 221 | ||
| 220 | int FAST_FUNC bb_putchar_stderr(char ch) | 222 | int 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 | ||
| 225 | ssize_t FAST_FUNC full_write1_str(const char *str) | 232 | ssize_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 | ||
| 317 | int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags) | 326 | int 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 | ||
| 111 | void* FAST_FUNC mmap_read(int fd, size_t size) | 112 | void* 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. |
| 337 | char* FAST_FUNC xasprintf(const char *format, ...) | 339 | char* 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 */ |
| 506 | ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, | 509 | ssize_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 |
| 519 | void FAST_FUNC xstat(const char *name, struct stat *stat_buf) | 523 | void 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 | ||
| 550 | int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) | 554 | #if !ENABLE_PLATFORM_MINGW32 |
| 555 | int 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 | ||
| 566 | int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) | 571 | int 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 | ||
| 727 | void FAST_FUNC xsettimeofday(const struct timeval *tv) | 734 | void 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 | ||
| 733 | void FAST_FUNC xgettimeofday(struct timeval *tv) | 741 | void 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 | ||
| 20 | char* FAST_FUNC xmalloc_readlink(const char *path) | 21 | char* 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 | |||
| 7 | lib-y:= | ||
| 8 | |||
| 9 | INSERT | ||
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 | |||
| 3 | yescrypt is very flexible, but configuring it optimally is complicated. | ||
| 4 | Here are some guidelines to simplify near-optimal configuration. We | ||
| 5 | start by listing the parameters and their typical values, and then give | ||
| 6 | currently recommended parameter sets by use case. | ||
| 7 | |||
| 8 | |||
| 9 | Parameters and their typical values. | ||
| 10 | |||
| 11 | Set flags (yescrypt flavor) to YESCRYPT_DEFAULTS to use the currently | ||
| 12 | recommended flavor. (Other flags values exist for compatibility and for | ||
| 13 | specialized cases where you think you know what you're doing.) | ||
| 14 | |||
| 15 | Set N (block count) based on target memory usage and running time, as | ||
| 16 | well as on the value of r (block size in 128 byte units). N must be a | ||
| 17 | power of two. | ||
| 18 | |||
| 19 | Set r (block size) to 8 (so that N is in KiB, which is convenient) or to | ||
| 20 | another small value (if more optimal or for fine-tuning of the total | ||
| 21 | size and/or running time). Reasonable values for r are from 8 to 96. | ||
| 22 | |||
| 23 | Set p (parallelism) to 1 meaning no thread-level parallelism within one | ||
| 24 | computation of yescrypt. (Use of thread-level parallelism within | ||
| 25 | yescrypt makes sense for ROM initialization and for key derivation at | ||
| 26 | high memory usage, but usually not for password hashing where | ||
| 27 | parallelism is available through concurrent authentication attempts. | ||
| 28 | Don't use p > 1 unnecessarily.) | ||
| 29 | |||
| 30 | Set t (time) to 0 to use the optimal running time for a given memory | ||
| 31 | usage. This will allow you to maximize the memory usage (the value of | ||
| 32 | N*r) while staying within your running time constraints. (Non-zero t | ||
| 33 | makes sense in specialized cases where you can't afford higher memory | ||
| 34 | usage but can afford more time.) | ||
| 35 | |||
| 36 | Set g (upgrades) to 0 because there have been no hash upgrades yet. | ||
| 37 | |||
| 38 | Set NROM (block count of ROM) to 0 unless you use a ROM (see below). | ||
| 39 | NROM must be a power of two. | ||
| 40 | |||
| 41 | |||
| 42 | Password hashing for user authentication, no ROM. | ||
| 43 | |||
| 44 | Small and fast (memory usage 2 MiB, performance like bcrypt cost 2^5 - | ||
| 45 | latency 2-3 ms and throughput 10,000+ per second on a 16-core server): | ||
| 46 | |||
| 47 | flags = YESCRYPT_DEFAULTS, N = 2048, r = 8, p = 1, t = 0, g = 0, NROM = 0 | ||
| 48 | |||
| 49 | Large and slow (memory usage 16 MiB, performance like bcrypt cost 2^8 - | ||
| 50 | latency 10-30 ms and throughput 1000+ per second on a 16-core server): | ||
| 51 | |||
| 52 | flags = YESCRYPT_DEFAULTS, N = 4096, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
| 53 | |||
| 54 | Of course, even heavier and slower settings are possible, if affordable. | ||
| 55 | Simply double the value of N as many times as needed. Since N must be a | ||
| 56 | power of two, you may use r (in the range of 8 to 32) or/and t (in the | ||
| 57 | range of 0 to 2) for fine-tuning the running time, but first bring N to | ||
| 58 | the maximum you can afford. If this feels too complicated, just use one | ||
| 59 | of the two parameter sets given above (preferably the second) as-is. | ||
| 60 | |||
| 61 | |||
| 62 | Password hashing for user authentication, with ROM. | ||
| 63 | |||
| 64 | It's similar to the above, except that you need to adjust r, set NROM, | ||
| 65 | and initialize the ROM. | ||
| 66 | |||
| 67 | First decide on a ROM size, such as making it a large portion of your | ||
| 68 | dedicated authentication servers' RAM sizes. Since NROM (block count) | ||
| 69 | must be a power of two, you might need to choose r (block size) based on | ||
| 70 | how your desired ROM size corresponds to a power of two. Also tuning | ||
| 71 | for performance on current hardware, you'll likely end up with r in the | ||
| 72 | range from slightly below 16 to 32. For example, to use 15/16 of a | ||
| 73 | server's 256 GiB RAM as ROM (thus, making it 240 GiB), you could use | ||
| 74 | r=15 or r=30. To use 23/24 of a server's 384 GiB RAM as ROM (thus, | ||
| 75 | making it 368 GiB), you'd use r=23. Then set NROM to your desired ROM | ||
| 76 | size in KiB divided by 128*r. Note that these examples might (or might | ||
| 77 | not) be too extreme, leaving little memory for the rest of the system. | ||
| 78 | You could as well opt for 7/8 with r=14 or 11/12 with r=11 or r=22. | ||
| 79 | |||
| 80 | Note that higher r may make placing of ROM in e.g. NVMe flash memory | ||
| 81 | instead of in RAM more reasonable (or less unreasonable) than it would | ||
| 82 | have been with a lower r. If this is a concern as it relates to | ||
| 83 | possible attacks and you do not intend to ever do it defensively, you | ||
| 84 | might want to keep r lower (e.g., prefer r=15 over r=30 in the example | ||
| 85 | above, even if 30 performs slightly faster). | ||
| 86 | |||
| 87 | Your adjustments to r, if you deviate from powers of two, will also | ||
| 88 | result in weirder memory usage per hash. Like 1.75 MiB at r=14 instead | ||
| 89 | of 2 MiB at r=8 that you would have used without a ROM. That's OK. | ||
| 90 | |||
| 91 | For ROM initialization, which you do with yescrypt_init_shared(), use | ||
| 92 | the same r and NROM that you'd later use for password hashing, choose p | ||
| 93 | based on your servers' physical and/or logical CPU count (maybe | ||
| 94 | considering eventual upgrades as you won't be able to change this later, | ||
| 95 | but without going unnecessarily high - e.g., p=28, p=56, or p=112 make | ||
| 96 | sense on servers that currently have 28 physical / 56 logical CPUs), and | ||
| 97 | set the rest of the parameters to: | ||
| 98 | |||
| 99 | flags = YESCRYPT_DEFAULTS, N = 0, t = 0, g = 0 | ||
| 100 | |||
| 101 | N is set to 0 because it isn't relevant during ROM initialization (you | ||
| 102 | can use different values of N for hashing passwords with the same ROM). | ||
| 103 | |||
| 104 | To keep the ROM in e.g. SysV shared memory and reuse it across your | ||
| 105 | authentication service restarts, you'd need to allocate the memory and | ||
| 106 | set the flags to "YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED". | ||
| 107 | |||
| 108 | For actual password hashing, you'd use your chosen values for N, r, | ||
| 109 | NROM, and set the rest of the parameters to: | ||
| 110 | |||
| 111 | flags = YESCRYPT_DEFAULTS, p = 1, t = 0, g = 0 | ||
| 112 | |||
| 113 | Note that although you'd use a large p for ROM initialization, you | ||
| 114 | should use p=1 for actual password hashing like you would without a ROM. | ||
| 115 | |||
| 116 | Do not forget to pass the ROM into the actual password hashing (and keep | ||
| 117 | r and NROM set accordingly). | ||
| 118 | |||
| 119 | Since N must be a power of two and r is dependent on ROM size, you may | ||
| 120 | use t (in the range of 0 to 2) for fine-tuning the running time, but | ||
| 121 | first bring N to the maximum you can afford. | ||
| 122 | |||
| 123 | If this feels too complicated, or even if it doesn't, please consider | ||
| 124 | engaging 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 | |||
| 131 | Use settings similar to those for password hashing without a ROM, but | ||
| 132 | adjusted for higher memory usage and running time, and optionally with | ||
| 133 | thread-level parallelism. | ||
| 134 | |||
| 135 | Small and fast (memory usage 128 MiB, running time under 100 ms on a | ||
| 136 | fast desktop): | ||
| 137 | |||
| 138 | flags = YESCRYPT_DEFAULTS, N = 32768, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
| 139 | |||
| 140 | Large and fast (memory usage 1 GiB, running time under 200 ms on a fast | ||
| 141 | quad-core desktop not including memory allocation overhead, under 250 ms | ||
| 142 | with the overhead included), but requires build with OpenMP support (or | ||
| 143 | otherwise will run as slow as yet be weaker than its p=1 alternative): | ||
| 144 | |||
| 145 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 0, g = 0, NROM = 0 | ||
| 146 | |||
| 147 | Large and slower (memory usage 1 GiB, running time under 300 ms on a | ||
| 148 | fast quad-core desktop not including memory allocation overhead, under | ||
| 149 | 350 ms with the overhead included), also requires build with OpenMP | ||
| 150 | support (or otherwise will run slower than the p=1 alternative below): | ||
| 151 | |||
| 152 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 2, g = 0, NROM = 0 | ||
| 153 | |||
| 154 | Large and slow (memory usage 1 GiB, running time under 600 ms on a fast | ||
| 155 | desktop not including memory allocation overhead, under 650 ms with the | ||
| 156 | overhead included): | ||
| 157 | |||
| 158 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
| 159 | |||
| 160 | Just like with password hashing, even heavier and slower settings are | ||
| 161 | possible, if affordable, and you achieve them by adjusting N, r, t in | ||
| 162 | the same way and in the same preferred ranges (please see the section on | ||
| 163 | password hashing without a ROM, above). Unlike with password hashing, | ||
| 164 | it makes some sense to go above t=2 if you expect that your users might | ||
| 165 | not be able to afford more memory but can afford more time. However, | ||
| 166 | increasing the memory usage provides better protection, and we don't | ||
| 167 | recommend forcing your users to wait for more than 1 second as they | ||
| 168 | could as well type more characters in that time. If this feels too | ||
| 169 | complicated, just use one of the above parameter sets as-is. | ||
| 170 | |||
| 171 | |||
| 172 | Amortization of memory allocation overhead. | ||
| 173 | |||
| 174 | It takes a significant fraction of yescrypt's total running time to | ||
| 175 | allocate memory from the operating system, especially considering that | ||
| 176 | the kernel zeroizes the memory before handing it over to your program. | ||
| 177 | |||
| 178 | Unless you naturally need to compute yescrypt just once per process, you | ||
| 179 | may achieve greater efficiency by fully using advanced yescrypt APIs | ||
| 180 | that let you preserve and reuse the memory allocation across yescrypt | ||
| 181 | invocations. This is done by reusing the structure pointed to by the | ||
| 182 | "yescrypt_local_t *local" argument of yescrypt_r() or yescrypt_kdf() | ||
| 183 | without calling yescrypt_free_local() inbetween the repeated invocations | ||
| 184 | of yescrypt. | ||
| 185 | |||
| 186 | |||
| 187 | YESCRYPT_DEFAULTS macro. | ||
| 188 | |||
| 189 | Please note that the value of the YESCRYPT_DEFAULTS macro might change | ||
| 190 | later, so if you use the macro like it's recommended here then for | ||
| 191 | results reproducible across versions you might need to store its value | ||
| 192 | somewhere along with the hashes or the encrypted data. | ||
| 193 | |||
| 194 | If you use yescrypt's standard hash string encoding, then yescrypt | ||
| 195 | already encodes and decodes this value for you, so you don't need to | ||
| 196 | worry 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 @@ | |||
| 1 | The yescrypt code in this directory is adapted from libxcrypt-4.4.38 | ||
| 2 | with minimal edits, hopefully making it easier to track | ||
| 3 | backports by resetting the tree to the commit which created this file, | ||
| 4 | then 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..dc748c968 --- /dev/null +++ b/libbb/yescrypt/alg-sha256.c | |||
| @@ -0,0 +1,91 @@ | |||
| 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 | */ | ||
| 33 | static void | ||
| 34 | PBKDF2_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 | long U[32 / sizeof(long)]; | ||
| 51 | long T[32 / sizeof(long)]; | ||
| 52 | // Do not make these ^^ uint64_t[]. Keep them long[]. | ||
| 53 | // Even though the XORing loop below is optimized out, | ||
| 54 | // gcc is not smart enough to realize that 64-bit alignment of the stack | ||
| 55 | // is no longer useful, and generates ~50 more bytes of code on i386... | ||
| 56 | uint32_t ivec; | ||
| 57 | size_t clen; | ||
| 58 | int k; | ||
| 59 | |||
| 60 | /* Generate INT(i). */ | ||
| 61 | i++; | ||
| 62 | ivec = SWAP_BE32(i); | ||
| 63 | |||
| 64 | /* Compute U_1 = PRF(P, S || INT(i)). */ | ||
| 65 | hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL); | ||
| 66 | //TODO: the above is a vararg function, might incur some ABI pain | ||
| 67 | //does libbb need a non-vararg version with just one (buf,len)? | ||
| 68 | |||
| 69 | if (c > 1) { | ||
| 70 | //in yescrypt, c is always 1, so this if() branch is optimized out | ||
| 71 | uint64_t j; | ||
| 72 | /* T_i = U_1 ... */ | ||
| 73 | memcpy(U, T, 32); | ||
| 74 | for (j = 2; j <= c; j++) { | ||
| 75 | /* Compute U_j. */ | ||
| 76 | hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); | ||
| 77 | /* ... xor U_j ... */ | ||
| 78 | for (k = 0; k < 32 / sizeof(long); k++) | ||
| 79 | T[k] ^= U[k]; | ||
| 80 | //TODO: xorbuf32_aligned_long(T, U); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | /* Copy as many bytes as necessary into buf. */ | ||
| 85 | clen = dkLen; | ||
| 86 | if (clen > 32) | ||
| 87 | clen = 32; | ||
| 88 | buf = mempcpy(buf, T, clen); | ||
| 89 | dkLen -= clen; | ||
| 90 | } | ||
| 91 | } | ||
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 | */ | ||
| 43 | static 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 | ||
| 108 | static 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 | ||
| 151 | static 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 */ | ||
| 219 | static 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 | |||
| 270 | static 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 | |||
| 293 | char *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 | |||
| 45 | typedef union { | ||
| 46 | uint32_t w[16]; | ||
| 47 | uint64_t d[8]; | ||
| 48 | } salsa20_blk_t; | ||
| 49 | |||
| 50 | static void salsa20_simd_shuffle( | ||
| 51 | const salsa20_blk_t *Bin, | ||
| 52 | salsa20_blk_t *Bout) | ||
| 53 | { | ||
| 54 | #define COMBINE(out, in1, in2) \ | ||
| 55 | do { \ | ||
| 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 | |||
| 69 | static void salsa20_simd_unshuffle( | ||
| 70 | const salsa20_blk_t *Bin, | ||
| 71 | salsa20_blk_t *Bout) | ||
| 72 | { | ||
| 73 | #define UNCOMBINE(out, in1, in2) \ | ||
| 74 | do { \ | ||
| 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) \ | ||
| 96 | do { \ | ||
| 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) \ | ||
| 108 | do { \ | ||
| 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 | */ | ||
| 120 | static 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) \ | ||
| 234 | do { \ | ||
| 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) \ | ||
| 246 | do { \ | ||
| 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) \ | ||
| 254 | do { \ | ||
| 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) \ | ||
| 264 | do { \ | ||
| 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 | */ | ||
| 276 | static 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 | |||
| 291 | static 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) \ | ||
| 329 | do { \ | ||
| 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 \ | ||
| 339 | do { \ | ||
| 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 \ | ||
| 347 | do { \ | ||
| 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 \ | ||
| 364 | do { \ | ||
| 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 \ | ||
| 371 | do { \ | ||
| 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 \ | ||
| 391 | do { \ | ||
| 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 | |||
| 410 | typedef 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 | */ | ||
| 422 | static 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 | |||
| 458 | static 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 | |||
| 499 | static 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 | */ | ||
| 543 | static 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 | ||
| 566 | static 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 | ||
| 695 | static 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 | */ | ||
| 784 | static 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 | ||
| 807 | static 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 | |||
| 890 | static 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 | |||
| 917 | static 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 | */ | ||
| 945 | static 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 | */ | ||
| 1158 | static | ||
| 1159 | int 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 | */ | ||
| 193 | typedef 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 | */ | ||
| 205 | typedef 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 | |||
| 215 | typedef 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 | */ | ||
| 243 | extern 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" | ||
