| /* |
| * Creates a bunch of files in the specified directory with the same |
| * hashvalue on-disk. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/time.h> |
| |
| #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) |
| |
| /* |
| * Implement a simple hash on a character string. |
| * Rotate the hash value by 7 bits, then XOR each character in. |
| * This is implemented with some source-level loop unrolling. |
| */ |
| static uint32_t xfs_da_hashname(const char *name, int namelen) |
| { |
| uint32_t hash; |
| |
| /* |
| * Do four characters at a time as long as we can. |
| */ |
| for (hash = 0; namelen >= 4; namelen -= 4, name += 4) |
| hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ |
| (name[3] << 0) ^ rol32(hash, 7 * 4); |
| |
| /* |
| * Now do the rest of the characters. |
| */ |
| switch (namelen) { |
| case 3: |
| return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ |
| rol32(hash, 7 * 3); |
| case 2: |
| return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); |
| case 1: |
| return (name[0] << 0) ^ rol32(hash, 7 * 1); |
| default: /* case 0: */ |
| return hash; |
| } |
| } |
| |
| static int is_invalid_char(char c) |
| { |
| return (c <= ' ' || c > '~' || c == '/' || (c >= 'A' && c <= 'Z')); |
| } |
| |
| static char random_char(void) |
| { |
| char c; |
| |
| /* get a character of "0"-"9" or "a"-"z" */ |
| |
| c = lrand48() % 36; |
| |
| return (c >= 10) ? c + 87 : c + 48; |
| } |
| |
| static int generate_names(const char *path, long amount, uint32_t desired_hash) |
| { |
| char **names; |
| char fullpath[PATH_MAX]; |
| char *filename; |
| long count; |
| long i; |
| uint32_t base_hash; |
| uint32_t hash; |
| |
| names = malloc(amount * sizeof(char *)); |
| if (!names) { |
| fprintf(stderr, "genhashnames: malloc(%lu) failed!\n", |
| amount * sizeof(char *)); |
| return 1; |
| } |
| |
| strcpy(fullpath, path); |
| filename = fullpath + strlen(fullpath); |
| if (filename[-1] != '/') |
| *filename++ = '/'; |
| |
| for (count = 0; count < amount; count++) { |
| for (;;) { |
| base_hash = 0; |
| for (i = 0; i < 6; i++) { |
| filename[i] = random_char(); |
| base_hash = filename[i] ^ rol32(base_hash, 7); |
| } |
| while (i < 200) { |
| filename[i] = random_char(); |
| base_hash = filename[i] ^ rol32(base_hash, 7); |
| i++; |
| hash = rol32(base_hash, 3) ^ desired_hash; |
| |
| filename[i] = (hash >> 28) | |
| (random_char() & 0xf0); |
| if (is_invalid_char(filename[i])) |
| continue; |
| |
| filename[i + 1] = (hash >> 21) & 0x7f; |
| if (is_invalid_char(filename[i + 1])) |
| continue; |
| filename[i + 2] = (hash >> 14) & 0x7f; |
| if (is_invalid_char(filename[i + 2])) |
| continue; |
| filename[i + 3] = (hash >> 7) & 0x7f; |
| if (is_invalid_char(filename[i + 3])) |
| continue; |
| filename[i + 4] = (hash ^ (filename[i] >> 4)) |
| & 0x7f; |
| if (is_invalid_char(filename[i + 4])) |
| continue; |
| break; |
| } |
| if (i < NAME_MAX) |
| break; |
| } |
| filename[i + 5] = '\0'; |
| if (xfs_da_hashname(filename, i + 5) != desired_hash) { |
| fprintf(stderr, "genhashnames: Hash mismatch!\n"); |
| return 1; |
| } |
| |
| for (i = 0; i < count; i++) { |
| if (strcmp(fullpath, names[i]) == 0) |
| break; |
| } |
| if (i == count) { |
| names[count] = strdup(fullpath); |
| puts(fullpath); |
| } else |
| count--; |
| } |
| return 0; |
| } |
| |
| static void usage(void) |
| { |
| fprintf(stderr, "Usage: genhashnames <directory> <amount> " |
| "[seed] [hashvalue]\n"); |
| exit(1); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| long seed; |
| uint32_t desired_hash; |
| |
| if (argc < 3 || argc > 5) |
| usage(); |
| |
| if (argc >= 4) |
| seed = strtol(argv[3], NULL, 0); |
| else { |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| seed = tv.tv_usec / 1000 + (tv.tv_sec % 1000) * 1000; |
| } |
| srand48(seed); |
| |
| /* |
| * always generate hash from random so if hash is specified, random |
| * sequence is the same as a randomly generated hash of the same value. |
| */ |
| desired_hash = (uint32_t)mrand48(); |
| if (argc >= 5) |
| desired_hash = (uint32_t)strtoul(argv[4], NULL, 0); |
| |
| fprintf(stderr, "seed = %ld, hash = 0x%08x\n", seed, desired_hash); |
| |
| return generate_names(argv[1], strtol(argv[2], NULL, 0), desired_hash); |
| } |