This is a small command-line utility that computes a 32-bit Fowler-Noll-Vo (FNV) hash of an input file supplied on the command line. The Fowler-Noll-Vo hash is a non-cryptographic hash function created by Glenn Fowler, Landon Curt Noll and Phong Vo. Compared to other hash functions, the FNV hash function is a small hashing function. The implementation in this package computes a 32-bit hash function from an input file and is implemented using AmigaOS functions - optionally benefiting from asyncio.library
if present.
The current implementation was written to be compiled with SAS/C but you can compile it with whatever tool available that has the required AmigaOS libraries and include files. You may need to download dev/c/AsyncIO.lha by Magnus Holmgren since it contains the required include files. If needed, the include files and libraries should be moved to the SAS/C folder (libs under libs, include under include, etc…).
After all the includes and libraries are setup correctly, you can change directory to src
and then issue the command:
sc link fnv32.c
and it should result in a fnv32
binary file.
After copying the binary to an executable path, issue:
fnv32 input.txt
where input.txt
is file.
The program should print out the FNV hash of the file.
You can also specify which bits to mask off but MASK
(the default is 32
):
fnv32 mask=16 input.txt
/*************************************************************************/ /* Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 */ /*************************************************************************/ /* */ /* fnv32 */ /* */ /* $VER: fnv32 1.0 (14 Jul 2015) by Wizardry and Steamworks */ /* */ /* Computes a 32-bit Fowler-Noll-Vo hash of a given input file. */ /* */ /* Compile using SASC: sc link fnv32.c */ /* */ /* More info on FNV: http://www.isthe.com/chongo/tech/comp/fnv/ */ /* */ /*************************************************************************/ #include <string.h> #include <stdlib.h> #include <proto/asyncio.h> #include <proto/dos.h> #include <proto/exec.h> GLOBAL TEXT version_string[] = "\0$VER: fnv32 1.0 (14 Jul 2015) by Wizardry and Steamworks"; /*************************************************************************/ /* Hash in chunks of 32 * 1024 for a 32-bit hash width. */ /*************************************************************************/ #define WIDTH 32 #define BUF_SIZE 32 * 1024 /*************************************************************************/ /* Magic prime and initialization vector. */ /*************************************************************************/ #define FNV_32_PRIME ((ULONG)0x01000193) #define FNV1_32_INIT ((ULONG)0x811c9dc5) /*************************************************************************/ /* Fowler-Noll-Vo hashing function. */ /*************************************************************************/ ULONG fnv_32_buf(void *buf, LONG len, ULONG hval) { unsigned char *bp = (UBYTE *)buf; unsigned char *be = bp + len; while(bp < be) { hval *= FNV_32_PRIME; hval ^= (ULONG)*bp++; } return hval; } /* mask is optional, path to file is not */ STATIC CONST TEXT template[] = "MASK=MASK/K/N,PATH/A"; enum { MASK, PATH, NUM_ARGS }; int main(int argc, char **argv) { struct Library *AsyncIOBase; LONG readsz; UBYTE *buf; APTR fh; /* initialize hash to 32-bit vector */ ULONG hval = FNV1_32_INIT; /* setup command-line arguments to retrieve file and mask */ LONG *arg_array; struct RDArgs *rdargs; STRPTR file; ULONG mask; /* allocate memory for arg array */ arg_array = AllocMem(NUM_ARGS, MEMF_ANY|MEMF_CLEAR); if(arg_array == NULL) { Printf("Unable to allocate memory.\n"); return 1; } /* read command-line arguments */ rdargs = ReadArgs(template, arg_array, NULL); if(rdargs == NULL) { FreeArgs(rdargs); return 1; } /* assign file */ file = (STRPTR)arg_array[PATH]; /* assign mask */ mask = (ULONG *)arg_array[MASK] != NULL ? *(ULONG *)arg_array[MASK] : WIDTH; FreeArgs(rdargs); /* if the mask is not between 0 and WIDTH (inclusive) then bail */ if(mask < 0 || mask > WIDTH) { Printf("The MASK parameter must be between 0 and %ld.\n", WIDTH); return 1; } /* setup mask */ switch(mask != (ULONG)WIDTH) { case TRUE: mask = (ULONG)((1 << mask) - 1); break; default: mask = (ULONG)0xffffffff; break; } /* allocate buffer */ buf = AllocMem(BUF_SIZE + 1, MEMF_ANY|MEMF_CLEAR); if(buf == NULL) { Printf("Unable to allocate memory.\n"); return 1; } /* attempt to open the asyncio library */ AsyncIOBase = OpenLibrary("asyncio.library", 0); /* either use asyncio library if available or regular file-handling */ switch(AsyncIOBase != NULL) { case TRUE: fh = OpenAsync(file, MODE_READ, BUF_SIZE); break; default: fh = (APTR)Open(file, MODE_OLDFILE); break; } /* the file could not be opened so bail */ if(fh == NULL) { Printf("Unable to open file: %s\n", file); if(AsyncIOBase != NULL) CloseLibrary(AsyncIOBase); return 1; } /* compute the hash by reading chunks */ switch(AsyncIOBase != NULL) { case TRUE: while((readsz = ReadAsync(fh, buf, BUF_SIZE)) > 0) hval = fnv_32_buf(buf, readsz, hval); break; default: while((readsz = Read((BPTR)fh, buf, BUF_SIZE)) > 0) hval = fnv_32_buf(buf, readsz, hval); break; } /* close file-handles */ switch(AsyncIOBase != NULL) { case TRUE: CloseAsync(fh); break; default: Close((BPTR)fh); break; } /* print the hash and mask it */ Printf("0x%08lx\n", hval & mask); /* graceful exit. */ return 0; }