aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/src/util.c')
-rw-r--r--examples/redis-unstable/src/util.c1774
1 files changed, 0 insertions, 1774 deletions
diff --git a/examples/redis-unstable/src/util.c b/examples/redis-unstable/src/util.c
deleted file mode 100644
index ba3d9d0..0000000
--- a/examples/redis-unstable/src/util.c
+++ /dev/null
@@ -1,1774 +0,0 @@
1/*
2 * Copyright (c) 2009-current, Redis Ltd.
3 * Copyright (c) 2012, Twitter, Inc.
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 are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * 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 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "fmacros.h"
32#include "fpconv_dtoa.h"
33#include "fast_float_strtod.h"
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <ctype.h>
38#include <limits.h>
39#include <math.h>
40#include <unistd.h>
41#include <sys/time.h>
42#include <float.h>
43#include <stdint.h>
44#include <errno.h>
45#include <time.h>
46#include <sys/stat.h>
47#include <dirent.h>
48#include <fcntl.h>
49#include <libgen.h>
50
51#include "util.h"
52#include "sha256.h"
53#include "config.h"
54
55#define UNUSED(x) ((void)(x))
56
57/* Selectively define static_assert. Attempt to avoid include server.h in this file. */
58#ifndef static_assert
59#define static_assert(expr, lit) extern char __static_assert_failure[(expr) ? 1:-1]
60#endif
61
62static_assert(UINTPTR_MAX == 0xffffffffffffffff || UINTPTR_MAX == 0xffffffff, "Unsupported pointer size");
63
64/* Glob-style pattern matching. */
65static int stringmatchlen_impl(const char *pattern, int patternLen,
66 const char *string, int stringLen, int nocase, int *skipLongerMatches, int nesting)
67{
68 /* Protection against abusive patterns. */
69 if (nesting > 1000) return 0;
70
71 while(patternLen && stringLen) {
72 switch(pattern[0]) {
73 case '*':
74 while (patternLen && pattern[1] == '*') {
75 pattern++;
76 patternLen--;
77 }
78 if (patternLen == 1)
79 return 1; /* match */
80 while(stringLen) {
81 if (stringmatchlen_impl(pattern+1, patternLen-1,
82 string, stringLen, nocase, skipLongerMatches, nesting+1))
83 return 1; /* match */
84 if (*skipLongerMatches)
85 return 0; /* no match */
86 string++;
87 stringLen--;
88 }
89 /* There was no match for the rest of the pattern starting
90 * from anywhere in the rest of the string. If there were
91 * any '*' earlier in the pattern, we can terminate the
92 * search early without trying to match them to longer
93 * substrings. This is because a longer match for the
94 * earlier part of the pattern would require the rest of the
95 * pattern to match starting later in the string, and we
96 * have just determined that there is no match for the rest
97 * of the pattern starting from anywhere in the current
98 * string. */
99 *skipLongerMatches = 1;
100 return 0; /* no match */
101 break;
102 case '?':
103 string++;
104 stringLen--;
105 break;
106 case '[':
107 {
108 int not, match;
109
110 pattern++;
111 patternLen--;
112 not = patternLen && pattern[0] == '^';
113 if (not) {
114 pattern++;
115 patternLen--;
116 }
117 match = 0;
118 while(1) {
119 if (patternLen >= 2 && pattern[0] == '\\') {
120 pattern++;
121 patternLen--;
122 if (pattern[0] == string[0])
123 match = 1;
124 } else if (patternLen == 0) {
125 pattern--;
126 patternLen++;
127 break;
128 } else if (pattern[0] == ']') {
129 break;
130 } else if (patternLen >= 3 && pattern[1] == '-') {
131 int start = pattern[0];
132 int end = pattern[2];
133 int c = string[0];
134 if (start > end) {
135 int t = start;
136 start = end;
137 end = t;
138 }
139 if (nocase) {
140 start = tolower(start);
141 end = tolower(end);
142 c = tolower(c);
143 }
144 pattern += 2;
145 patternLen -= 2;
146 if (c >= start && c <= end)
147 match = 1;
148 } else {
149 if (!nocase) {
150 if (pattern[0] == string[0])
151 match = 1;
152 } else {
153 if (tolower((int)pattern[0]) == tolower((int)string[0]))
154 match = 1;
155 }
156 }
157 pattern++;
158 patternLen--;
159 }
160 if (not)
161 match = !match;
162 if (!match)
163 return 0; /* no match */
164 string++;
165 stringLen--;
166 break;
167 }
168 case '\\':
169 if (patternLen >= 2) {
170 pattern++;
171 patternLen--;
172 }
173 /* fall through */
174 default:
175 if (!nocase) {
176 if (pattern[0] != string[0])
177 return 0; /* no match */
178 } else {
179 if (tolower((int)pattern[0]) != tolower((int)string[0]))
180 return 0; /* no match */
181 }
182 string++;
183 stringLen--;
184 break;
185 }
186 pattern++;
187 patternLen--;
188 if (stringLen == 0) {
189 while(patternLen && *pattern == '*') {
190 pattern++;
191 patternLen--;
192 }
193 break;
194 }
195 }
196 if (patternLen == 0 && stringLen == 0)
197 return 1;
198 return 0;
199}
200
201/*
202 * glob-style pattern matching to check if a given pattern fully includes
203 * the prefix of a string. For the match to succeed, the pattern must end with
204 * an unescaped '*' character.
205 *
206 * Returns: 1 if the `pattern` fully matches the `prefixStr`. Returns 0 otherwise.
207 */
208int prefixmatch(const char *pattern, int patternLen,
209 const char *prefixStr, int prefixStrLen, int nocase) {
210 int skipLongerMatches = 0;
211
212 /* Step 1: Verify if the pattern matches the prefix string completely. */
213 if (!stringmatchlen_impl(pattern, patternLen, prefixStr, prefixStrLen, nocase, &skipLongerMatches, 0))
214 return 0;
215
216 /* Step 2: Verify that the pattern ends with an unescaped '*', indicating
217 * it can match any suffix of the string beyond the prefix. This check
218 * remains outside stringmatchlen_impl() to keep its complexity manageable.
219 */
220 if (patternLen == 0 || pattern[patternLen - 1] != '*' )
221 return 0;
222
223 /* Count backward the number of consecutive backslashes preceding the '*'
224 * to determine if the '*' is escaped. */
225 int backslashCount = 0;
226 for (int i = patternLen - 2; i >= 0; i--) {
227 if (pattern[i] == '\\')
228 ++backslashCount;
229 else
230 break; /* Stop counting when a non-backslash character is found. */
231 }
232
233 /* Return 1 if the '*' is not escaped (i.e., even count), 0 otherwise. */
234 return (backslashCount % 2 == 0);
235}
236
237/* Glob-style pattern matching to a string. */
238int stringmatchlen(const char *pattern, int patternLen,
239 const char *string, int stringLen, int nocase) {
240 int skipLongerMatches = 0;
241 return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches,0);
242}
243
244int stringmatch(const char *pattern, const char *string, int nocase) {
245 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
246}
247
248/* Fuzz stringmatchlen() trying to crash it with bad input. */
249int stringmatchlen_fuzz_test(void) {
250 char str[32];
251 char pat[32];
252 int cycles = 10000000;
253 int total_matches = 0;
254 while(cycles--) {
255 int strlen = rand() % sizeof(str);
256 int patlen = rand() % sizeof(pat);
257 for (int j = 0; j < strlen; j++) str[j] = rand() % 128;
258 for (int j = 0; j < patlen; j++) pat[j] = rand() % 128;
259 total_matches += stringmatchlen(pat, patlen, str, strlen, 0);
260 }
261 return total_matches;
262}
263
264
265/* Convert a string representing an amount of memory into the number of
266 * bytes, so for instance memtoull("1Gb") will return 1073741824 that is
267 * (1024*1024*1024).
268 *
269 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
270 * set to 0. On error the function return value is 0, regardless of the
271 * fact 'err' is NULL or not. */
272unsigned long long memtoull(const char *p, int *err) {
273 const char *u;
274 char buf[128];
275 long mul; /* unit multiplier */
276 unsigned long long val;
277 unsigned int digits;
278
279 if (err) *err = 0;
280
281 /* Search the first non digit character. */
282 u = p;
283 if (*u == '-') {
284 if (err) *err = 1;
285 return 0;
286 }
287 while(*u && isdigit(*u)) u++;
288 if (*u == '\0' || !strcasecmp(u,"b")) {
289 mul = 1;
290 } else if (!strcasecmp(u,"k")) {
291 mul = 1000;
292 } else if (!strcasecmp(u,"kb")) {
293 mul = 1024;
294 } else if (!strcasecmp(u,"m")) {
295 mul = 1000*1000;
296 } else if (!strcasecmp(u,"mb")) {
297 mul = 1024*1024;
298 } else if (!strcasecmp(u,"g")) {
299 mul = 1000L*1000*1000;
300 } else if (!strcasecmp(u,"gb")) {
301 mul = 1024L*1024*1024;
302 } else {
303 if (err) *err = 1;
304 return 0;
305 }
306
307 /* Copy the digits into a buffer, we'll use strtoll() to convert
308 * the digit (without the unit) into a number. */
309 digits = u-p;
310 if (digits >= sizeof(buf)) {
311 if (err) *err = 1;
312 return 0;
313 }
314 memcpy(buf,p,digits);
315 buf[digits] = '\0';
316
317 char *endptr;
318 errno = 0;
319 val = strtoull(buf,&endptr,10);
320 if ((val == 0 && errno == EINVAL) || *endptr != '\0') {
321 if (err) *err = 1;
322 return 0;
323 }
324 return val*mul;
325}
326
327/* Search a memory buffer for any set of bytes, like strpbrk().
328 * Returns pointer to first found char or NULL.
329 */
330const char *mempbrk(const char *s, size_t len, const char *chars, size_t charslen) {
331 for (size_t j = 0; j < len; j++) {
332 for (size_t n = 0; n < charslen; n++)
333 if (s[j] == chars[n]) return &s[j];
334 }
335
336 return NULL;
337}
338
339/* Modify the buffer replacing all occurrences of chars from the 'from'
340 * set with the corresponding char in the 'to' set. Always returns s.
341 */
342char *memmapchars(char *s, size_t len, const char *from, const char *to, size_t setlen) {
343 for (size_t j = 0; j < len; j++) {
344 for (size_t i = 0; i < setlen; i++) {
345 if (s[j] == from[i]) {
346 s[j] = to[i];
347 break;
348 }
349 }
350 }
351 return s;
352}
353
354/* Return the number of digits of 'v' when converted to string in radix 10.
355 * See ll2string() for more information. */
356uint32_t digits10(uint64_t v) {
357 if (v < 10) return 1;
358 if (v < 100) return 2;
359 if (v < 1000) return 3;
360 if (v < 1000000000000UL) {
361 if (v < 100000000UL) {
362 if (v < 1000000) {
363 if (v < 10000) return 4;
364 return 5 + (v >= 100000);
365 }
366 return 7 + (v >= 10000000UL);
367 }
368 if (v < 10000000000UL) {
369 return 9 + (v >= 1000000000UL);
370 }
371 return 11 + (v >= 100000000000UL);
372 }
373 return 12 + digits10(v / 1000000000000UL);
374}
375
376/* Like digits10() but for signed values. */
377uint32_t sdigits10(int64_t v) {
378 if (v < 0) {
379 /* Abs value of LLONG_MIN requires special handling. */
380 uint64_t uv = (v != LLONG_MIN) ?
381 (uint64_t)-v : ((uint64_t) LLONG_MAX)+1;
382 return digits10(uv)+1; /* +1 for the minus. */
383 } else {
384 return digits10(v);
385 }
386}
387
388/* Convert a long long into a string. Returns the number of
389 * characters needed to represent the number.
390 * If the buffer is not big enough to store the string, 0 is returned. */
391int ll2string(char *dst, size_t dstlen, long long svalue) {
392 unsigned long long value;
393 int negative = 0;
394
395 /* The ull2string function with 64bit unsigned integers for simplicity, so
396 * we convert the number here and remember if it is negative. */
397 if (svalue < 0) {
398 if (svalue != LLONG_MIN) {
399 value = -svalue;
400 } else {
401 value = ((unsigned long long) LLONG_MAX)+1;
402 }
403 if (dstlen < 2)
404 goto err;
405 negative = 1;
406 dst[0] = '-';
407 dst++;
408 dstlen--;
409 } else {
410 value = svalue;
411 }
412
413 /* Converts the unsigned long long value to string*/
414 int length = ull2string(dst, dstlen, value);
415 if (length == 0) return 0;
416 return length + negative;
417
418err:
419 /* force add Null termination */
420 if (dstlen > 0)
421 dst[0] = '\0';
422 return 0;
423}
424
425/* Convert a unsigned long long into a string. Returns the number of
426 * characters needed to represent the number.
427 * If the buffer is not big enough to store the string, 0 is returned.
428 *
429 * Based on the following article (that apparently does not provide a
430 * novel approach but only publicizes an already used technique):
431 *
432 * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 */
433int ull2string(char *dst, size_t dstlen, unsigned long long value) {
434 static const char digits[201] =
435 "0001020304050607080910111213141516171819"
436 "2021222324252627282930313233343536373839"
437 "4041424344454647484950515253545556575859"
438 "6061626364656667686970717273747576777879"
439 "8081828384858687888990919293949596979899";
440
441 /* Check length. */
442 uint32_t length = digits10(value);
443 if (length >= dstlen) goto err;;
444
445 /* Null term. */
446 uint32_t next = length - 1;
447 dst[next + 1] = '\0';
448 while (value >= 100) {
449 int const i = (value % 100) * 2;
450 value /= 100;
451 dst[next] = digits[i + 1];
452 dst[next - 1] = digits[i];
453 next -= 2;
454 }
455
456 /* Handle last 1-2 digits. */
457 if (value < 10) {
458 dst[next] = '0' + (uint32_t) value;
459 } else {
460 int i = (uint32_t) value * 2;
461 dst[next] = digits[i + 1];
462 dst[next - 1] = digits[i];
463 }
464 return length;
465err:
466 /* force add Null termination */
467 if (dstlen > 0)
468 dst[0] = '\0';
469 return 0;
470}
471
472/* Convert a string into a long long. Returns 1 if the string could be parsed
473 * into a (non-overflowing) long long, 0 otherwise. The value will be set to
474 * the parsed value when appropriate.
475 *
476 * Note that this function demands that the string strictly represents
477 * a long long: no spaces or other characters before or after the string
478 * representing the number are accepted, nor zeroes at the start if not
479 * for the string "0" representing the zero number.
480 *
481 * Because of its strictness, it is safe to use this function to check if
482 * you can convert a string into a long long, and obtain back the string
483 * from the number without any loss in the string representation. */
484int string2ll(const char *s, size_t slen, long long *value) {
485 const char *p = s;
486 size_t plen = 0;
487 int negative = 0;
488 unsigned long long v;
489
490 /* A string of zero length or excessive length is not a valid number. */
491 if (plen == slen || slen >= LONG_STR_SIZE)
492 return 0;
493
494 /* Special case: first and only digit is 0. */
495 if (slen == 1 && p[0] == '0') {
496 if (value != NULL) *value = 0;
497 return 1;
498 }
499
500 /* Handle negative numbers: just set a flag and continue like if it
501 * was a positive number. Later convert into negative. */
502 if (p[0] == '-') {
503 negative = 1;
504 p++; plen++;
505
506 /* Abort on only a negative sign. */
507 if (plen == slen)
508 return 0;
509 }
510
511 /* First digit should be 1-9, otherwise the string should just be 0. */
512 if (p[0] >= '1' && p[0] <= '9') {
513 v = p[0]-'0';
514 p++; plen++;
515 } else {
516 return 0;
517 }
518
519 /* Parse all the other digits, checking for overflow at every step. */
520 while (plen < slen && p[0] >= '0' && p[0] <= '9') {
521 if (v > (ULLONG_MAX / 10)) /* Overflow. */
522 return 0;
523 v *= 10;
524
525 if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
526 return 0;
527 v += p[0]-'0';
528
529 p++; plen++;
530 }
531
532 /* Return if not all bytes were used. */
533 if (plen < slen)
534 return 0;
535
536 /* Convert to negative if needed, and do the final overflow check when
537 * converting from unsigned long long to long long. */
538 if (negative) {
539 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
540 return 0;
541 if (value != NULL) *value = -v;
542 } else {
543 if (v > LLONG_MAX) /* Overflow. */
544 return 0;
545 if (value != NULL) *value = v;
546 }
547 return 1;
548}
549
550/* Helper function to convert a string to an unsigned long long value.
551 * The function attempts to use the faster string2ll() function inside
552 * Redis: if it fails, strtoull() is used instead. The function returns
553 * 1 if the conversion happened successfully or 0 if the number is
554 * invalid or out of range. */
555int string2ull(const char *s, unsigned long long *value) {
556 long long ll;
557 if (string2ll(s,strlen(s),&ll)) {
558 if (ll < 0) return 0; /* Negative values are out of range. */
559 *value = ll;
560 return 1;
561 }
562 errno = 0;
563 char *endptr = NULL;
564 *value = strtoull(s,&endptr,10);
565 if (errno == EINVAL || errno == ERANGE || !(*s != '\0' && *endptr == '\0'))
566 return 0; /* strtoull() failed. */
567 return 1; /* Conversion done! */
568}
569
570/* Convert a string into a long. Returns 1 if the string could be parsed into a
571 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
572 * value when appropriate. */
573int string2l(const char *s, size_t slen, long *lval) {
574 long long llval;
575
576 if (!string2ll(s,slen,&llval))
577 return 0;
578
579 if (llval < LONG_MIN || llval > LONG_MAX)
580 return 0;
581
582 *lval = (long)llval;
583 return 1;
584}
585
586/* return 1 if c>= start && c <= end, 0 otherwise*/
587static int safe_is_c_in_range(char c, char start, char end) {
588 if (c >= start && c <= end) return 1;
589 return 0;
590}
591
592static int base_16_char_type(char c) {
593 if (safe_is_c_in_range(c, '0', '9')) return 0;
594 if (safe_is_c_in_range(c, 'a', 'f')) return 1;
595 if (safe_is_c_in_range(c, 'A', 'F')) return 2;
596 return -1;
597}
598
599/** This is an async-signal safe version of string2l to convert unsigned long to string.
600 * The function translates @param src until it reaches a value that is not 0-9, a-f or A-F, or @param we read slen characters.
601 * On successes writes the result to @param result_output and returns 1.
602 * if the string represents an overflow value, return -1. */
603int string2ul_base16_async_signal_safe(const char *src, size_t slen, unsigned long *result_output) {
604 static char ascii_to_dec[] = {'0', 'a' - 10, 'A' - 10};
605
606 int char_type = 0;
607 size_t curr_char_idx = 0;
608 unsigned long result = 0;
609 int base = 16;
610 while ((-1 != (char_type = base_16_char_type(src[curr_char_idx]))) &&
611 curr_char_idx < slen) {
612 unsigned long curr_val = src[curr_char_idx] - ascii_to_dec[char_type];
613 if ((result > ULONG_MAX / base) || (result > (ULONG_MAX - curr_val)/base)) /* Overflow. */
614 return -1;
615 result = result * base + curr_val;
616 ++curr_char_idx;
617 }
618
619 *result_output = result;
620 return 1;
621}
622
623/* Convert a string into a double. Returns 1 if the string could be parsed
624 * into a (non-overflowing) double, 0 otherwise. The value will be set to
625 * the parsed value when appropriate.
626 *
627 * Note that this function demands that the string strictly represents
628 * a double: no spaces or other characters before or after the string
629 * representing the number are accepted. */
630int string2ld(const char *s, size_t slen, long double *dp) {
631 char buf[MAX_LONG_DOUBLE_CHARS];
632 long double value;
633 char *eptr;
634
635 if (slen == 0 || slen >= sizeof(buf)) return 0;
636 memcpy(buf,s,slen);
637 buf[slen] = '\0';
638
639 errno = 0;
640 value = strtold(buf, &eptr);
641 if (isspace(buf[0]) || eptr[0] != '\0' ||
642 (size_t)(eptr-buf) != slen ||
643 (errno == ERANGE &&
644 (value == HUGE_VAL || value == -HUGE_VAL || fpclassify(value) == FP_ZERO)) ||
645 errno == EINVAL ||
646 isnan(value))
647 return 0;
648
649 if (dp) *dp = value;
650 return 1;
651}
652
653/* Convert a string into a double. Returns 1 if the string could be parsed
654 * into a (non-overflowing) double, 0 otherwise. The value will be set to
655 * the parsed value when appropriate.
656 *
657 * Note that this function demands that the string strictly represents
658 * a double: no spaces or other characters before or after the string
659 * representing the number are accepted. */
660int string2d(const char *s, size_t slen, double *dp) {
661 errno = 0;
662 char *eptr;
663 /* Fast path to reject empty strings, or strings starting by space explicitly */
664 if (unlikely(slen == 0 ||
665 isspace(((const char*)s)[0])))
666 return 0;
667 *dp = fast_float_strtod(s, &eptr);
668 /* If `fast_float_strtod` didn't consume full input, try `strtod`
669 * Given fast_float does not support hexadecimal strings representation */
670 if (unlikely((size_t)(eptr - (char*)s) != slen)) {
671 char *fallback_eptr;
672 *dp = strtod(s, &fallback_eptr);
673 if ((size_t)(fallback_eptr - (char*)s) != slen) return 0;
674 }
675 if (unlikely(errno == EINVAL ||
676 (errno == ERANGE &&
677 (*dp == HUGE_VAL || *dp == -HUGE_VAL || fpclassify(*dp) == FP_ZERO)) ||
678 isnan(*dp)))
679 return 0;
680 return 1;
681}
682
683/* Returns 1 if the double value can safely be represented in long long without
684 * precision loss, in which case the corresponding long long is stored in the out variable. */
685int double2ll(double d, long long *out) {
686#if (DBL_MANT_DIG >= 52) && (DBL_MANT_DIG <= 63) && (LLONG_MAX == 0x7fffffffffffffffLL)
687 /* Check if the float is in a safe range to be casted into a
688 * long long. We are assuming that long long is 64 bit here.
689 * Also we are assuming that there are no implementations around where
690 * double has precision < 52 bit.
691 *
692 * Under this assumptions we test if a double is inside a range
693 * where casting to long long is safe. Then using two castings we
694 * make sure the decimal part is zero. If all this is true we can use
695 * integer without precision loss.
696 *
697 * Note that numbers above 2^52 and below 2^63 use all the fraction bits as real part,
698 * and the exponent bits are positive, which means the "decimal" part must be 0.
699 * i.e. all double values in that range are representable as a long without precision loss,
700 * but not all long values in that range can be represented as a double.
701 * we only care about the first part here. */
702 if (d < (double)(-LLONG_MAX/2) || d > (double)(LLONG_MAX/2))
703 return 0;
704 long long ll = d;
705 if (ll == d) {
706 *out = ll;
707 return 1;
708 }
709#endif
710 return 0;
711}
712
713/* Convert a double to a string representation. Returns the number of bytes
714 * required. The representation should always be parsable by strtod(3).
715 * This function does not support human-friendly formatting like ld2string
716 * does. It is intended mainly to be used inside t_zset.c when writing scores
717 * into a listpack representing a sorted set. */
718int d2string(char *buf, size_t len, double value) {
719 if (isnan(value)) {
720 /* Libc in some systems will format nan in a different way,
721 * like nan, -nan, NAN, nan(char-sequence).
722 * So we normalize it and create a single nan form in an explicit way. */
723 len = snprintf(buf,len,"nan");
724 } else if (isinf(value)) {
725 /* Libc in odd systems (Hi Solaris!) will format infinite in a
726 * different way, so better to handle it in an explicit way. */
727 if (value < 0)
728 len = snprintf(buf,len,"-inf");
729 else
730 len = snprintf(buf,len,"inf");
731 } else if (value == 0) {
732 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
733 if (1.0/value < 0)
734 len = snprintf(buf,len,"-0");
735 else
736 len = snprintf(buf,len,"0");
737 } else {
738 long long lvalue;
739 /* Integer printing function is much faster, check if we can safely use it. */
740 if (double2ll(value, &lvalue))
741 len = ll2string(buf,len,lvalue);
742 else {
743 len = fpconv_dtoa(value, buf);
744 buf[len] = '\0';
745 }
746 }
747
748 return len;
749}
750
751/* Convert a double into a string with 'fractional_digits' digits after the dot precision.
752 * This is an optimized version of snprintf "%.<fractional_digits>f".
753 * We convert the double to long and multiply it by 10 ^ <fractional_digits> to shift
754 * the decimal places.
755 * Note that multiply it of input value by 10 ^ <fractional_digits> can overflow but on the scenario
756 * that we currently use within redis this that is not possible.
757 * After we get the long representation we use the logic from ull2string function on this file
758 * which is based on the following article:
759 * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
760 *
761 * Input values:
762 * char: the buffer to store the string representation
763 * dstlen: the buffer length
764 * dvalue: the input double
765 * fractional_digits: the number of fractional digits after the dot precision. between 1 and 17
766 *
767 * Return values:
768 * Returns the number of characters needed to represent the number.
769 * If the buffer is not big enough to store the string, 0 is returned.
770 */
771int fixedpoint_d2string(char *dst, size_t dstlen, double dvalue, int fractional_digits) {
772 if (fractional_digits < 1 || fractional_digits > 17)
773 goto err;
774 /* min size of 2 ( due to 0. ) + n fractional_digitits + \0 */
775 if ((int)dstlen < (fractional_digits+3))
776 goto err;
777 if (dvalue == 0) {
778 dst[0] = '0';
779 dst[1] = '.';
780 memset(dst + 2, '0', fractional_digits);
781 dst[fractional_digits+2] = '\0';
782 return fractional_digits + 2;
783 }
784 /* scale and round */
785 static double powers_of_ten[] = {1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0,
786 10000000.0, 100000000.0, 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0,
787 10000000000000.0, 100000000000000.0, 1000000000000000.0, 10000000000000000.0,
788 100000000000000000.0 };
789 long long svalue = llrint(dvalue * powers_of_ten[fractional_digits]);
790 unsigned long long value;
791 /* write sign */
792 int negative = 0;
793 if (svalue < 0) {
794 if (svalue != LLONG_MIN) {
795 value = -svalue;
796 } else {
797 value = ((unsigned long long) LLONG_MAX)+1;
798 }
799 if (dstlen < 2)
800 goto err;
801 negative = 1;
802 dst[0] = '-';
803 dst++;
804 dstlen--;
805 } else {
806 value = svalue;
807 }
808
809 static const char digitsd[201] =
810 "0001020304050607080910111213141516171819"
811 "2021222324252627282930313233343536373839"
812 "4041424344454647484950515253545556575859"
813 "6061626364656667686970717273747576777879"
814 "8081828384858687888990919293949596979899";
815
816 /* Check length. */
817 uint32_t ndigits = digits10(value);
818 if (ndigits >= dstlen) goto err;
819 int integer_digits = ndigits - fractional_digits;
820 /* Fractional only check to avoid representing 0.7750 as .7750.
821 * This means we need to increment the length and store 0 as the first character.
822 */
823 if (integer_digits < 1) {
824 dst[0] = '0';
825 integer_digits = 1;
826 }
827 dst[integer_digits] = '.';
828 int size = integer_digits + 1 + fractional_digits;
829 /* fill with 0 from fractional digits until size */
830 memset(dst + integer_digits + 1, '0', fractional_digits);
831 int next = size - 1;
832 while (value >= 100) {
833 int const i = (value % 100) * 2;
834 value /= 100;
835 dst[next] = digitsd[i + 1];
836 dst[next - 1] = digitsd[i];
837 next -= 2;
838 /* dot position */
839 if (next == integer_digits) {
840 next--;
841 }
842 }
843
844 /* Handle last 1-2 digits. */
845 if (value < 10) {
846 dst[next] = '0' + (uint32_t) value;
847 } else {
848 int i = (uint32_t) value * 2;
849 dst[next] = digitsd[i + 1];
850 dst[next - 1] = digitsd[i];
851 }
852 /* Null term. */
853 dst[size] = '\0';
854 return size + negative;
855err:
856 /* force add Null termination */
857 if (dstlen > 0)
858 dst[0] = '\0';
859 return 0;
860}
861
862/* Trims off trailing zeros from a string representing a double. */
863int trimDoubleString(char *buf, size_t len) {
864 if (strchr(buf,'.') != NULL) {
865 char *p = buf+len-1;
866 while(*p == '0') {
867 p--;
868 len--;
869 }
870 if (*p == '.') len--;
871 }
872 buf[len] = '\0';
873 return len;
874}
875
876/* Create a string object from a long double.
877 * If mode is humanfriendly it does not use exponential format and trims trailing
878 * zeroes at the end (may result in loss of precision).
879 * If mode is default exp format is used and the output of snprintf()
880 * is not modified (may result in loss of precision).
881 * If mode is hex hexadecimal format is used (no loss of precision)
882 *
883 * The function returns the length of the string or zero if there was not
884 * enough buffer room to store it. */
885int ld2string(char *buf, size_t len, long double value, ld2string_mode mode) {
886 size_t l = 0;
887
888 if (isinf(value)) {
889 /* Libc in odd systems (Hi Solaris!) will format infinite in a
890 * different way, so better to handle it in an explicit way. */
891 if (len < 5) goto err; /* No room. 5 is "-inf\0" */
892 if (value > 0) {
893 memcpy(buf,"inf",3);
894 l = 3;
895 } else {
896 memcpy(buf,"-inf",4);
897 l = 4;
898 }
899 } else if (isnan(value)) {
900 /* Libc in some systems will format nan in a different way,
901 * like nan, -nan, NAN, nan(char-sequence).
902 * So we normalize it and create a single nan form in an explicit way. */
903 if (len < 4) goto err; /* No room. 4 is "nan\0" */
904 memcpy(buf, "nan", 3);
905 l = 3;
906 } else {
907 switch (mode) {
908 case LD_STR_AUTO:
909 l = snprintf(buf,len,"%.17Lg",value);
910 if (l+1 > len) goto err;; /* No room. */
911 break;
912 case LD_STR_HEX:
913 l = snprintf(buf,len,"%La",value);
914 if (l+1 > len) goto err; /* No room. */
915 break;
916 case LD_STR_HUMAN:
917 /* We use 17 digits precision since with 128 bit floats that precision
918 * after rounding is able to represent most small decimal numbers in a
919 * way that is "non surprising" for the user (that is, most small
920 * decimal numbers will be represented in a way that when converted
921 * back into a string are exactly the same as what the user typed.) */
922 l = snprintf(buf,len,"%.17Lf",value);
923 if (l+1 > len) goto err; /* No room. */
924 /* Now remove trailing zeroes after the '.' */
925 if (strchr(buf,'.') != NULL) {
926 char *p = buf+l-1;
927 while(*p == '0') {
928 p--;
929 l--;
930 }
931 if (*p == '.') l--;
932 }
933 if (l == 2 && buf[0] == '-' && buf[1] == '0') {
934 buf[0] = '0';
935 l = 1;
936 }
937 break;
938 default: goto err; /* Invalid mode. */
939 }
940 }
941 buf[l] = '\0';
942 return l;
943err:
944 /* force add Null termination */
945 if (len > 0)
946 buf[0] = '\0';
947 return 0;
948}
949
950/* Get random bytes, attempts to get an initial seed from /dev/urandom and
951 * the uses a one way hash function in counter mode to generate a random
952 * stream. However if /dev/urandom is not available, a weaker seed is used.
953 *
954 * This function is not thread safe, since the state is global. */
955void getRandomBytes(unsigned char *p, size_t len) {
956 /* Global state. */
957 static int seed_initialized = 0;
958 static unsigned char seed[64]; /* 512 bit internal block size. */
959 static uint64_t counter = 0; /* The counter we hash with the seed. */
960
961 if (!seed_initialized) {
962 /* Initialize a seed and use SHA1 in counter mode, where we hash
963 * the same seed with a progressive counter. For the goals of this
964 * function we just need non-colliding strings, there are no
965 * cryptographic security needs. */
966 FILE *fp = fopen("/dev/urandom","r");
967 if (fp == NULL || fread(seed,sizeof(seed),1,fp) != 1) {
968 /* Revert to a weaker seed, and in this case reseed again
969 * at every call.*/
970 for (unsigned int j = 0; j < sizeof(seed); j++) {
971 struct timeval tv;
972 gettimeofday(&tv,NULL);
973 pid_t pid = getpid();
974 seed[j] = tv.tv_sec ^ tv.tv_usec ^ pid ^ (long)fp;
975 }
976 } else {
977 seed_initialized = 1;
978 }
979 if (fp) fclose(fp);
980 }
981
982 while(len) {
983 /* This implements SHA256-HMAC. */
984 unsigned char digest[SHA256_BLOCK_SIZE];
985 unsigned char kxor[64];
986 unsigned int copylen =
987 len > SHA256_BLOCK_SIZE ? SHA256_BLOCK_SIZE : len;
988
989 /* IKEY: key xored with 0x36. */
990 memcpy(kxor,seed,sizeof(kxor));
991 for (unsigned int i = 0; i < sizeof(kxor); i++) kxor[i] ^= 0x36;
992
993 /* Obtain HASH(IKEY||MESSAGE). */
994 SHA256_CTX ctx;
995 sha256_init(&ctx);
996 sha256_update(&ctx,kxor,sizeof(kxor));
997 sha256_update(&ctx,(unsigned char*)&counter,sizeof(counter));
998 sha256_final(&ctx,digest);
999
1000 /* OKEY: key xored with 0x5c. */
1001 memcpy(kxor,seed,sizeof(kxor));
1002 for (unsigned int i = 0; i < sizeof(kxor); i++) kxor[i] ^= 0x5C;
1003
1004 /* Obtain HASH(OKEY || HASH(IKEY||MESSAGE)). */
1005 sha256_init(&ctx);
1006 sha256_update(&ctx,kxor,sizeof(kxor));
1007 sha256_update(&ctx,digest,SHA256_BLOCK_SIZE);
1008 sha256_final(&ctx,digest);
1009
1010 /* Increment the counter for the next iteration. */
1011 counter++;
1012
1013 memcpy(p,digest,copylen);
1014 len -= copylen;
1015 p += copylen;
1016 }
1017}
1018
1019/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
1020 * given execution of Redis, so that if you are talking with an instance
1021 * having run_id == A, and you reconnect and it has run_id == B, you can be
1022 * sure that it is either a different instance or it was restarted. */
1023void getRandomHexChars(char *p, size_t len) {
1024 char *charset = "0123456789abcdef";
1025 size_t j;
1026
1027 getRandomBytes((unsigned char*)p,len);
1028 for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F];
1029}
1030
1031/* Given the filename, return the absolute path as an SDS string, or NULL
1032 * if it fails for some reason. Note that "filename" may be an absolute path
1033 * already, this will be detected and handled correctly.
1034 *
1035 * The function does not try to normalize everything, but only the obvious
1036 * case of one or more "../" appearing at the start of "filename"
1037 * relative path. */
1038sds getAbsolutePath(char *filename) {
1039 char cwd[1024];
1040 sds abspath;
1041 sds relpath = sdsnew(filename);
1042
1043 relpath = sdstrim(relpath," \r\n\t");
1044 if (relpath[0] == '/') return relpath; /* Path is already absolute. */
1045
1046 /* If path is relative, join cwd and relative path. */
1047 if (getcwd(cwd,sizeof(cwd)) == NULL) {
1048 sdsfree(relpath);
1049 return NULL;
1050 }
1051 abspath = sdsnew(cwd);
1052 if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/')
1053 abspath = sdscat(abspath,"/");
1054
1055 /* At this point we have the current path always ending with "/", and
1056 * the trimmed relative path. Try to normalize the obvious case of
1057 * trailing ../ elements at the start of the path.
1058 *
1059 * For every "../" we find in the filename, we remove it and also remove
1060 * the last element of the cwd, unless the current cwd is "/". */
1061 while (sdslen(relpath) >= 3 &&
1062 relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/')
1063 {
1064 sdsrange(relpath,3,-1);
1065 if (sdslen(abspath) > 1) {
1066 char *p = abspath + sdslen(abspath)-2;
1067 int trimlen = 1;
1068
1069 while(*p != '/') {
1070 p--;
1071 trimlen++;
1072 }
1073 sdsrange(abspath,0,-(trimlen+1));
1074 }
1075 }
1076
1077 /* Finally glue the two parts together. */
1078 abspath = sdscatsds(abspath,relpath);
1079 sdsfree(relpath);
1080 return abspath;
1081}
1082
1083/*
1084 * Gets the proper timezone in a more portable fashion
1085 * i.e timezone variables are linux specific.
1086 */
1087long getTimeZone(void) {
1088#if defined(__linux__) || defined(__sun)
1089 return timezone;
1090#else
1091 struct timezone tz;
1092
1093 gettimeofday(NULL, &tz);
1094
1095 return tz.tz_minuteswest * 60L;
1096#endif
1097}
1098
1099/* Return true if the specified path is just a file basename without any
1100 * relative or absolute path. This function just checks that no / or \
1101 * character exists inside the specified path, that's enough in the
1102 * environments where Redis runs. */
1103int pathIsBaseName(char *path) {
1104 return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;
1105}
1106
1107int fileExist(char *filename) {
1108 struct stat statbuf;
1109 return stat(filename, &statbuf) == 0 && S_ISREG(statbuf.st_mode);
1110}
1111
1112int dirExists(char *dname) {
1113 struct stat statbuf;
1114 return stat(dname, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
1115}
1116
1117int dirCreateIfMissing(char *dname) {
1118 if (mkdir(dname, 0755) != 0) {
1119 if (errno != EEXIST) {
1120 return -1;
1121 } else if (!dirExists(dname)) {
1122 errno = ENOTDIR;
1123 return -1;
1124 }
1125 }
1126 return 0;
1127}
1128
1129int dirRemove(char *dname) {
1130 DIR *dir;
1131 struct stat stat_entry;
1132 struct dirent *entry;
1133 char full_path[PATH_MAX + 1];
1134
1135 if ((dir = opendir(dname)) == NULL) {
1136 return -1;
1137 }
1138
1139 while ((entry = readdir(dir)) != NULL) {
1140 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
1141
1142 snprintf(full_path, sizeof(full_path), "%s/%s", dname, entry->d_name);
1143
1144 int fd = open(full_path, O_RDONLY|O_NONBLOCK);
1145 if (fd == -1) {
1146 closedir(dir);
1147 return -1;
1148 }
1149
1150 if (fstat(fd, &stat_entry) == -1) {
1151 close(fd);
1152 closedir(dir);
1153 return -1;
1154 }
1155 close(fd);
1156
1157 if (S_ISDIR(stat_entry.st_mode) != 0) {
1158 if (dirRemove(full_path) == -1) {
1159 closedir(dir);
1160 return -1;
1161 }
1162 continue;
1163 }
1164
1165 if (unlink(full_path) != 0) {
1166 closedir(dir);
1167 return -1;
1168 }
1169 }
1170
1171 if (rmdir(dname) != 0) {
1172 closedir(dir);
1173 return -1;
1174 }
1175
1176 closedir(dir);
1177 return 0;
1178}
1179
1180sds makePath(char *path, char *filename) {
1181 return sdscatfmt(sdsempty(), "%s/%s", path, filename);
1182}
1183
1184/* Given the filename, sync the corresponding directory.
1185 *
1186 * Usually a portable and safe pattern to overwrite existing files would be like:
1187 * 1. create a new temp file (on the same file system!)
1188 * 2. write data to the temp file
1189 * 3. fsync() the temp file
1190 * 4. rename the temp file to the appropriate name
1191 * 5. fsync() the containing directory */
1192int fsyncFileDir(const char *filename) {
1193#ifdef _AIX
1194 /* AIX is unable to fsync a directory */
1195 return 0;
1196#endif
1197 char temp_filename[PATH_MAX + 1];
1198 char *dname;
1199 int dir_fd;
1200
1201 if (strlen(filename) > PATH_MAX) {
1202 errno = ENAMETOOLONG;
1203 return -1;
1204 }
1205
1206 /* In the glibc implementation dirname may modify their argument. */
1207 memcpy(temp_filename, filename, strlen(filename) + 1);
1208 dname = dirname(temp_filename);
1209
1210 dir_fd = open(dname, O_RDONLY);
1211 if (dir_fd == -1) {
1212 /* Some OSs don't allow us to open directories at all, just
1213 * ignore the error in that case */
1214 if (errno == EISDIR) {
1215 return 0;
1216 }
1217 return -1;
1218 }
1219 /* Some OSs don't allow us to fsync directories at all, so we can ignore
1220 * those errors. */
1221 if (redis_fsync(dir_fd) == -1 && !(errno == EBADF || errno == EINVAL)) {
1222 int save_errno = errno;
1223 close(dir_fd);
1224 errno = save_errno;
1225 return -1;
1226 }
1227
1228 close(dir_fd);
1229 return 0;
1230}
1231
1232 /* free OS pages backed by file */
1233int reclaimFilePageCache(int fd, size_t offset, size_t length) {
1234#ifdef HAVE_FADVISE
1235 int ret = posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED);
1236 if (ret) {
1237 errno = ret;
1238 return -1;
1239 }
1240 return 0;
1241#else
1242 UNUSED(fd);
1243 UNUSED(offset);
1244 UNUSED(length);
1245 return 0;
1246#endif
1247}
1248
1249/** An async signal safe version of fgets().
1250 * Has the same behaviour as standard fgets(): reads a line from fd and stores it into the dest buffer.
1251 * It stops when either (buff_size-1) characters are read, the newline character is read, or the end-of-file is reached,
1252 * whichever comes first.
1253 *
1254 * On success, the function returns the same dest parameter. If the End-of-File is encountered and no characters have
1255 * been read, the contents of dest remain unchanged and a null pointer is returned.
1256 * If an error occurs, a null pointer is returned. */
1257char *fgets_async_signal_safe(char *dest, int buff_size, int fd) {
1258 for (int i = 0; i < buff_size; i++) {
1259 /* Read one byte */
1260 ssize_t bytes_read_count = read(fd, dest + i, 1);
1261 /* On EOF or error return NULL */
1262 if (bytes_read_count < 1) {
1263 return NULL;
1264 }
1265 /* we found the end of the line. */
1266 if (dest[i] == '\n') {
1267 break;
1268 }
1269 }
1270 return dest;
1271}
1272
1273static const char HEX[] = "0123456789abcdef";
1274
1275static char *u2string_async_signal_safe(int _base, uint64_t val, char *buf) {
1276 uint32_t base = (uint32_t) _base;
1277 *buf-- = 0;
1278 do {
1279 *buf-- = HEX[val % base];
1280 } while ((val /= base) != 0);
1281 return buf + 1;
1282}
1283
1284static char *i2string_async_signal_safe(int base, int64_t val, char *buf) {
1285 char *orig_buf = buf;
1286 const int32_t is_neg = (val < 0);
1287 *buf-- = 0;
1288
1289 if (is_neg) {
1290 val = -val;
1291 }
1292 if (is_neg && base == 16) {
1293 int ix;
1294 val -= 1;
1295 for (ix = 0; ix < 16; ++ix)
1296 buf[-ix] = '0';
1297 }
1298
1299 do {
1300 *buf-- = HEX[val % base];
1301 } while ((val /= base) != 0);
1302
1303 if (is_neg && base == 10) {
1304 *buf-- = '-';
1305 }
1306
1307 if (is_neg && base == 16) {
1308 int ix;
1309 buf = orig_buf - 1;
1310 for (ix = 0; ix < 16; ++ix, --buf) {
1311 /* *INDENT-OFF* */
1312 switch (*buf) {
1313 case '0': *buf = 'f'; break;
1314 case '1': *buf = 'e'; break;
1315 case '2': *buf = 'd'; break;
1316 case '3': *buf = 'c'; break;
1317 case '4': *buf = 'b'; break;
1318 case '5': *buf = 'a'; break;
1319 case '6': *buf = '9'; break;
1320 case '7': *buf = '8'; break;
1321 case '8': *buf = '7'; break;
1322 case '9': *buf = '6'; break;
1323 case 'a': *buf = '5'; break;
1324 case 'b': *buf = '4'; break;
1325 case 'c': *buf = '3'; break;
1326 case 'd': *buf = '2'; break;
1327 case 'e': *buf = '1'; break;
1328 case 'f': *buf = '0'; break;
1329 }
1330 /* *INDENT-ON* */
1331 }
1332 }
1333 return buf + 1;
1334}
1335
1336static const char *check_longlong_async_signal_safe(const char *fmt, int32_t *have_longlong) {
1337 *have_longlong = 0;
1338 if (*fmt == 'l') {
1339 fmt++;
1340 if (*fmt != 'l') {
1341 *have_longlong = (sizeof(long) == sizeof(int64_t));
1342 } else {
1343 fmt++;
1344 *have_longlong = 1;
1345 }
1346 }
1347 return fmt;
1348}
1349
1350int vsnprintf_async_signal_safe(char *to, size_t size, const char *format, va_list ap) {
1351 char *start = to;
1352 char *end = start + size - 1;
1353 for (; *format; ++format) {
1354 int32_t have_longlong = 0;
1355 if (*format != '%') {
1356 if (to == end) { /* end of buffer */
1357 break;
1358 }
1359 *to++ = *format; /* copy ordinary char */
1360 continue;
1361 }
1362 ++format; /* skip '%' */
1363
1364 format = check_longlong_async_signal_safe(format, &have_longlong);
1365
1366 switch (*format) {
1367 case 'd':
1368 case 'i':
1369 case 'u':
1370 case 'x':
1371 case 'p':
1372 {
1373 int64_t ival = 0;
1374 uint64_t uval = 0;
1375 if (*format == 'p')
1376 have_longlong = (sizeof(void *) == sizeof(uint64_t));
1377 if (have_longlong) {
1378 if (*format == 'u') {
1379 uval = va_arg(ap, uint64_t);
1380 } else {
1381 ival = va_arg(ap, int64_t);
1382 }
1383 } else {
1384 if (*format == 'u') {
1385 uval = va_arg(ap, uint32_t);
1386 } else {
1387 ival = va_arg(ap, int32_t);
1388 }
1389 }
1390
1391 {
1392 char buff[22];
1393 const int base = (*format == 'x' || *format == 'p') ? 16 : 10;
1394
1395/* *INDENT-OFF* */
1396 char *val_as_str = (*format == 'u') ?
1397 u2string_async_signal_safe(base, uval, &buff[sizeof(buff) - 1]) :
1398 i2string_async_signal_safe(base, ival, &buff[sizeof(buff) - 1]);
1399/* *INDENT-ON* */
1400
1401 /* Strip off "ffffffff" if we have 'x' format without 'll' */
1402 if (*format == 'x' && !have_longlong && ival < 0) {
1403 val_as_str += 8;
1404 }
1405
1406 while (*val_as_str && to < end) {
1407 *to++ = *val_as_str++;
1408 }
1409 continue;
1410 }
1411 }
1412 case 's':
1413 {
1414 const char *val = va_arg(ap, char *);
1415 if (!val) {
1416 val = "(null)";
1417 }
1418 while (*val && to < end) {
1419 *to++ = *val++;
1420 }
1421 continue;
1422 }
1423 }
1424 }
1425 *to = 0;
1426 return (int)(to - start);
1427}
1428
1429int snprintf_async_signal_safe(char *to, size_t n, const char *fmt, ...) {
1430 int result;
1431 va_list args;
1432 va_start(args, fmt);
1433 result = vsnprintf_async_signal_safe(to, n, fmt, args);
1434 va_end(args);
1435 return result;
1436}
1437
1438#ifdef REDIS_TEST
1439#include <assert.h>
1440#include <sys/mman.h>
1441#include "testhelp.h"
1442
1443static void test_string2ll(void) {
1444 char buf[32];
1445 long long v;
1446
1447 /* May not start with +. */
1448 redis_strlcpy(buf,"+1",sizeof(buf));
1449 assert(string2ll(buf,strlen(buf),&v) == 0);
1450
1451 /* Leading space. */
1452 redis_strlcpy(buf," 1",sizeof(buf));
1453 assert(string2ll(buf,strlen(buf),&v) == 0);
1454
1455 /* Trailing space. */
1456 redis_strlcpy(buf,"1 ",sizeof(buf));
1457 assert(string2ll(buf,strlen(buf),&v) == 0);
1458
1459 /* May not start with 0. */
1460 redis_strlcpy(buf,"01",sizeof(buf));
1461 assert(string2ll(buf,strlen(buf),&v) == 0);
1462
1463 redis_strlcpy(buf,"-1",sizeof(buf));
1464 assert(string2ll(buf,strlen(buf),&v) == 1);
1465 assert(v == -1);
1466
1467 redis_strlcpy(buf,"0",sizeof(buf));
1468 assert(string2ll(buf,strlen(buf),&v) == 1);
1469 assert(v == 0);
1470
1471 redis_strlcpy(buf,"1",sizeof(buf));
1472 assert(string2ll(buf,strlen(buf),&v) == 1);
1473 assert(v == 1);
1474
1475 redis_strlcpy(buf,"99",sizeof(buf));
1476 assert(string2ll(buf,strlen(buf),&v) == 1);
1477 assert(v == 99);
1478
1479 redis_strlcpy(buf,"-99",sizeof(buf));
1480 assert(string2ll(buf,strlen(buf),&v) == 1);
1481 assert(v == -99);
1482
1483 redis_strlcpy(buf,"-9223372036854775808",sizeof(buf));
1484 assert(string2ll(buf,strlen(buf),&v) == 1);
1485 assert(v == LLONG_MIN);
1486
1487 redis_strlcpy(buf,"-9223372036854775809",sizeof(buf)); /* overflow */
1488 assert(string2ll(buf,strlen(buf),&v) == 0);
1489
1490 redis_strlcpy(buf,"9223372036854775807",sizeof(buf));
1491 assert(string2ll(buf,strlen(buf),&v) == 1);
1492 assert(v == LLONG_MAX);
1493
1494 redis_strlcpy(buf,"9223372036854775808",sizeof(buf)); /* overflow */
1495 assert(string2ll(buf,strlen(buf),&v) == 0);
1496}
1497
1498static void test_string2l(void) {
1499 char buf[32];
1500 long v;
1501
1502 /* May not start with +. */
1503 redis_strlcpy(buf,"+1",sizeof(buf));
1504 assert(string2l(buf,strlen(buf),&v) == 0);
1505
1506 /* May not start with 0. */
1507 redis_strlcpy(buf,"01",sizeof(buf));
1508 assert(string2l(buf,strlen(buf),&v) == 0);
1509
1510 redis_strlcpy(buf,"-1",sizeof(buf));
1511 assert(string2l(buf,strlen(buf),&v) == 1);
1512 assert(v == -1);
1513
1514 redis_strlcpy(buf,"0",sizeof(buf));
1515 assert(string2l(buf,strlen(buf),&v) == 1);
1516 assert(v == 0);
1517
1518 redis_strlcpy(buf,"1",sizeof(buf));
1519 assert(string2l(buf,strlen(buf),&v) == 1);
1520 assert(v == 1);
1521
1522 redis_strlcpy(buf,"99",sizeof(buf));
1523 assert(string2l(buf,strlen(buf),&v) == 1);
1524 assert(v == 99);
1525
1526 redis_strlcpy(buf,"-99",sizeof(buf));
1527 assert(string2l(buf,strlen(buf),&v) == 1);
1528 assert(v == -99);
1529
1530#if LONG_MAX != LLONG_MAX
1531 redis_strlcpy(buf,"-2147483648",sizeof(buf));
1532 assert(string2l(buf,strlen(buf),&v) == 1);
1533 assert(v == LONG_MIN);
1534
1535 redis_strlcpy(buf,"-2147483649",sizeof(buf)); /* overflow */
1536 assert(string2l(buf,strlen(buf),&v) == 0);
1537
1538 redis_strlcpy(buf,"2147483647",sizeof(buf));
1539 assert(string2l(buf,strlen(buf),&v) == 1);
1540 assert(v == LONG_MAX);
1541
1542 redis_strlcpy(buf,"2147483648",sizeof(buf)); /* overflow */
1543 assert(string2l(buf,strlen(buf),&v) == 0);
1544#endif
1545}
1546
1547static void test_string2d(void) {
1548 char buf[1024];
1549 double v;
1550
1551 /* Valid hexadecimal value. */
1552 redis_strlcpy(buf,"0x0p+0",sizeof(buf));
1553 assert(string2d(buf,strlen(buf),&v) == 1);
1554 assert(v == 0.0);
1555
1556 redis_strlcpy(buf,"0x1p+0",sizeof(buf));
1557 assert(string2d(buf,strlen(buf),&v) == 1);
1558 assert(v == 1.0);
1559
1560 /* Valid floating-point numbers */
1561 redis_strlcpy(buf, "1.5", sizeof(buf));
1562 assert(string2d(buf, strlen(buf), &v) == 1);
1563 assert(v == 1.5);
1564
1565 redis_strlcpy(buf, "-3.14", sizeof(buf));
1566 assert(string2d(buf, strlen(buf), &v) == 1);
1567 assert(v == -3.14);
1568
1569 redis_strlcpy(buf, "2.0e10", sizeof(buf));
1570 assert(string2d(buf, strlen(buf), &v) == 1);
1571 assert(v == 2.0e10);
1572
1573 redis_strlcpy(buf, "1e-3", sizeof(buf));
1574 assert(string2d(buf, strlen(buf), &v) == 1);
1575 assert(v == 0.001);
1576
1577 /* Valid integer */
1578 redis_strlcpy(buf, "42", sizeof(buf));
1579 assert(string2d(buf, strlen(buf), &v) == 1);
1580 assert(v == 42.0);
1581
1582 /* Invalid cases */
1583 /* Empty. */
1584 redis_strlcpy(buf, "", sizeof(buf));
1585 assert(string2d(buf, strlen(buf), &v) == 0);
1586
1587 /* Starting by space. */
1588 redis_strlcpy(buf, " 1.23", sizeof(buf));
1589 assert(string2d(buf, strlen(buf), &v) == 0);
1590
1591 /* Invalid hexadecimal format. */
1592 redis_strlcpy(buf, "0x1.2g", sizeof(buf));
1593 assert(string2d(buf, strlen(buf), &v) == 0);
1594
1595 /* Hexadecimal NaN */
1596 redis_strlcpy(buf, "0xNan", sizeof(buf));
1597 assert(string2d(buf, strlen(buf), &v) == 0);
1598
1599 /* overflow. */
1600 redis_strlcpy(buf,"23456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789",sizeof(buf));
1601 assert(string2d(buf,strlen(buf),&v) == 0);
1602}
1603
1604static void test_ll2string(void) {
1605 char buf[32];
1606 long long v;
1607 int sz;
1608
1609 v = 0;
1610 sz = ll2string(buf, sizeof buf, v);
1611 assert(sz == 1);
1612 assert(!strcmp(buf, "0"));
1613
1614 v = -1;
1615 sz = ll2string(buf, sizeof buf, v);
1616 assert(sz == 2);
1617 assert(!strcmp(buf, "-1"));
1618
1619 v = 99;
1620 sz = ll2string(buf, sizeof buf, v);
1621 assert(sz == 2);
1622 assert(!strcmp(buf, "99"));
1623
1624 v = -99;
1625 sz = ll2string(buf, sizeof buf, v);
1626 assert(sz == 3);
1627 assert(!strcmp(buf, "-99"));
1628
1629 v = -2147483648;
1630 sz = ll2string(buf, sizeof buf, v);
1631 assert(sz == 11);
1632 assert(!strcmp(buf, "-2147483648"));
1633
1634 v = LLONG_MIN;
1635 sz = ll2string(buf, sizeof buf, v);
1636 assert(sz == 20);
1637 assert(!strcmp(buf, "-9223372036854775808"));
1638
1639 v = LLONG_MAX;
1640 sz = ll2string(buf, sizeof buf, v);
1641 assert(sz == 19);
1642 assert(!strcmp(buf, "9223372036854775807"));
1643}
1644
1645static void test_ld2string(void) {
1646 char buf[32];
1647 long double v;
1648 int sz;
1649
1650 v = 0.0 / 0.0;
1651 sz = ld2string(buf, sizeof(buf), v, LD_STR_AUTO);
1652 assert(sz == 3);
1653 assert(!strcmp(buf, "nan"));
1654}
1655
1656static void test_fixedpoint_d2string(void) {
1657 char buf[32];
1658 double v;
1659 int sz;
1660 v = 0.0;
1661 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1662 assert(sz == 6);
1663 assert(!strcmp(buf, "0.0000"));
1664 sz = fixedpoint_d2string(buf, sizeof buf, v, 1);
1665 assert(sz == 3);
1666 assert(!strcmp(buf, "0.0"));
1667 /* set junk in buffer */
1668 memset(buf,'A',32);
1669 v = 0.0001;
1670 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1671 assert(sz == 6);
1672 assert(buf[sz] == '\0');
1673 assert(!strcmp(buf, "0.0001"));
1674 /* set junk in buffer */
1675 memset(buf,'A',32);
1676 v = 6.0642951598391699e-05;
1677 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1678 assert(sz == 6);
1679 assert(buf[sz] == '\0');
1680 assert(!strcmp(buf, "0.0001"));
1681 v = 0.01;
1682 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1683 assert(sz == 6);
1684 assert(!strcmp(buf, "0.0100"));
1685 sz = fixedpoint_d2string(buf, sizeof buf, v, 1);
1686 assert(sz == 3);
1687 assert(!strcmp(buf, "0.0"));
1688 v = -0.01;
1689 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1690 assert(sz == 7);
1691 assert(!strcmp(buf, "-0.0100"));
1692 v = -0.1;
1693 sz = fixedpoint_d2string(buf, sizeof buf, v, 1);
1694 assert(sz == 4);
1695 assert(!strcmp(buf, "-0.1"));
1696 v = 0.1;
1697 sz = fixedpoint_d2string(buf, sizeof buf, v, 1);
1698 assert(sz == 3);
1699 assert(!strcmp(buf, "0.1"));
1700 v = 0.01;
1701 sz = fixedpoint_d2string(buf, sizeof buf, v, 17);
1702 assert(sz == 19);
1703 assert(!strcmp(buf, "0.01000000000000000"));
1704 v = 10.01;
1705 sz = fixedpoint_d2string(buf, sizeof buf, v, 4);
1706 assert(sz == 7);
1707 assert(!strcmp(buf, "10.0100"));
1708 /* negative tests */
1709 sz = fixedpoint_d2string(buf, sizeof buf, v, 18);
1710 assert(sz == 0);
1711 sz = fixedpoint_d2string(buf, sizeof buf, v, 0);
1712 assert(sz == 0);
1713 sz = fixedpoint_d2string(buf, 1, v, 1);
1714 assert(sz == 0);
1715}
1716
1717#if defined(__linux__)
1718/* Since fadvise and mincore is only supported in specific platforms like
1719 * Linux, we only verify the fadvise mechanism works in Linux */
1720static int cache_exist(int fd) {
1721 unsigned char flag;
1722 void *m = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
1723 assert(m);
1724 assert(mincore(m, 4096, &flag) == 0);
1725 munmap(m, 4096);
1726 /* the least significant bit of the byte will be set if the corresponding
1727 * page is currently resident in memory */
1728 return flag&1;
1729}
1730
1731static void test_reclaimFilePageCache(void) {
1732 char *tmpfile = "/tmp/redis-reclaim-cache-test";
1733 int fd = open(tmpfile, O_RDWR|O_CREAT, 0644);
1734 assert(fd >= 0);
1735
1736 /* test write file */
1737 char buf[4] = "foo";
1738 assert(write(fd, buf, sizeof(buf)) > 0);
1739 assert(cache_exist(fd));
1740 assert(redis_fsync(fd) == 0);
1741 assert(reclaimFilePageCache(fd, 0, 0) == 0);
1742 assert(!cache_exist(fd));
1743
1744 /* test read file */
1745 assert(pread(fd, buf, sizeof(buf), 0) > 0);
1746 assert(cache_exist(fd));
1747 assert(reclaimFilePageCache(fd, 0, 0) == 0);
1748 assert(!cache_exist(fd));
1749
1750 unlink(tmpfile);
1751 printf("reclaimFilePageCach test is ok\n");
1752}
1753#endif
1754
1755int utilTest(int argc, char **argv, int flags) {
1756 UNUSED(argc);
1757 UNUSED(argv);
1758 UNUSED(flags);
1759
1760 test_string2ll();
1761 test_string2l();
1762 test_string2d();
1763 test_ll2string();
1764 test_ld2string();
1765 test_fixedpoint_d2string();
1766#if defined(__linux__)
1767 if (!(flags & REDIS_TEST_VALGRIND)) {
1768 test_reclaimFilePageCache();
1769 }
1770#endif
1771 printf("Done testing util\n");
1772 return 0;
1773}
1774#endif