Generate a randomish name in the same directory as *NAME. If *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be that returned by a previous call and is thus already almost set up and equal to *NAME; otherwise, allocate a new name and put its address into both *NAMEALLOC and *NAME. */
| 1547 | that returned by a previous call and is thus already almost set up |
| 1548 | and equal to *NAME; otherwise, allocate a new name and put its |
| 1549 | address into both *NAMEALLOC and *NAME. */ |
| 1550 | static void |
| 1551 | random_dirent(char const **name, char **namealloc) |
| 1552 | { |
| 1553 | char const *src = *name; |
| 1554 | char *dst = *namealloc; |
| 1555 | static char const prefix[] = ".zic"; |
| 1556 | static char const alphabet[] = |
| 1557 | "abcdefghijklmnopqrstuvwxyz" |
| 1558 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 1559 | "0123456789"; |
| 1560 | enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 }; |
| 1561 | int suffixlen = 6; |
| 1562 | char const *lastslash = strrchr(src, '/'); |
| 1563 | ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0; |
| 1564 | int i; |
| 1565 | uint_fast64_t r; |
| 1566 | uint_fast64_t base = alphabetlen; |
| 1567 | |
| 1568 | /* BASE**6 */ |
| 1569 | uint_fast64_t base__6 = base * base * base * base * base * base; |
| 1570 | |
| 1571 | /* The largest uintmax_t that is a multiple of BASE**6. Any random |
| 1572 | uintmax_t value that is this value or greater, yields a biased |
| 1573 | remainder when divided by BASE**6. UNFAIR_MIN equals the |
| 1574 | mathematical value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6) |
| 1575 | computed without overflow. */ |
| 1576 | uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); |
| 1577 | |
| 1578 | if (!dst) { |
| 1579 | char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); |
| 1580 | cp = mempcpy(cp, src, dirlen); |
| 1581 | cp = mempcpy(cp, prefix, prefixlen); |
| 1582 | cp[suffixlen] = '\0'; |
| 1583 | *name = *namealloc = dst; |
| 1584 | } |
| 1585 | |
| 1586 | for (;; check_for_signal()) { |
| 1587 | r = get_rand_u64(); |
| 1588 | if (r < unfair_min) |
| 1589 | break; |
| 1590 | } |
| 1591 | |
| 1592 | for (i = 0; i < suffixlen; i++) { |
| 1593 | dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen]; |
| 1594 | r /= alphabetlen; |
| 1595 | } |
| 1596 | } |
| 1597 | |
| 1598 | /* For diagnostics the directory, and file name relative to that |
no test coverage detected