From owner-svn-soc-all@FreeBSD.ORG Wed May 23 20:59:33 2012 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from socsvn.FreeBSD.org (unknown [IPv6:2001:4f8:fff6::2f]) by hub.freebsd.org (Postfix) with SMTP id AA7891065672 for ; Wed, 23 May 2012 20:59:31 +0000 (UTC) (envelope-from gpf@FreeBSD.org) Received: by socsvn.FreeBSD.org (sSMTP sendmail emulation); Wed, 23 May 2012 20:59:31 +0000 Date: Wed, 23 May 2012 20:59:31 +0000 From: gpf@FreeBSD.org To: svn-soc-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <20120523205931.AA7891065672@hub.freebsd.org> Cc: Subject: socsvn commit: r236229 - soc2012/gpf/misc X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 May 2012 20:59:33 -0000 Author: gpf Date: Wed May 23 20:59:30 2012 New Revision: 236229 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=236229 Log: test_checksum.c to test validity of .pefs.checksum file. output from this program's pefs_print_hash_table() should be checked against output from sbin/pefs' pefs_print_hash_table(). They should match of course. Code just passed a test with a 100 files. Added: soc2012/gpf/misc/ soc2012/gpf/misc/test_checksum.c Added: soc2012/gpf/misc/test_checksum.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2012/gpf/misc/test_checksum.c Wed May 23 20:59:30 2012 (r236229) @@ -0,0 +1,412 @@ +/*- + * Copyright (c) 2012 Efstratios Karatzas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PEFS_INTEGRITY_DEBUG +#if defined (PEFS_INTEGRITY_DEBUG) +#define dprintf(a) printf a +#else +#define dprintf(a) (void)0 +#endif + +#define NARGS 2 +#define ERROR 1 +#define MAXPATHLEN 1024 +#define PEFS_CHECKSUM_FILE_VERSION 0xDD +#define PEFS_HASH_BYTE_ALIGNMENT 512 + +LIST_HEAD(file_header_head, file_header); +TAILQ_HEAD(checksum_head, checksum); + +struct checksum_file_header { + uint8_t version; + uint8_t reserved; + uint8_t hash_len; + uint8_t hash_algo[8]; + uint8_t offset_to_hash_table; + uint32_t hash_table_size; +}; + +struct checksum { + unsigned char *hash; + TAILQ_ENTRY(checksum) checksum_entries; +}; + +struct file_header { + uint32_t nhashes; + uint64_t file_id; + char path[MAXPATHLEN]; + LIST_ENTRY(file_header) bucket_entries; + uint32_t offset_to_checksums; + struct checksum_head checksums; +}; + +struct bucket { + struct file_header_head file_headers; + uint32_t offset_to_chain; + uint32_t nelements; + uint32_t elements_loaded; +}; + +struct hash_table { + struct bucket *buckets; + uint32_t size; /* how many buckets */ + uint32_t nelements; +}; + + +static int +pefs_allocate_hash_table(struct hash_table *checksum_hash_tablep, uint32_t size) +{ + uint32_t i; + + checksum_hash_tablep->size = size; + checksum_hash_tablep->buckets = malloc (size * sizeof(struct bucket)); + + if (checksum_hash_tablep->buckets == NULL) { + perror("memory allocation error"); + return (ERROR); + } + + for (i = 0; i < checksum_hash_tablep->size; i++) { + checksum_hash_tablep->buckets[i].nelements = 0; + checksum_hash_tablep->buckets[i].elements_loaded = 0; + LIST_INIT(&(checksum_hash_tablep->buckets[i].file_headers)); + } + + return (0); +} + +static void +pefs_add_to_bucket(struct bucket *bucketp, struct file_header *fhp) +{ + struct file_header *elementp; + struct file_header *last; + + if (bucketp->elements_loaded == 0) + LIST_INSERT_HEAD(&(bucketp->file_headers), fhp, bucket_entries); + else { + LIST_FOREACH(elementp, &(bucketp->file_headers), bucket_entries) { + last = elementp; + } + LIST_INSERT_AFTER(last, fhp, bucket_entries); + } + + bucketp->elements_loaded++; +} + +static void +pefs_add_to_file_header(struct file_header *fhp, struct checksum *csp) +{ + TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries); +} + +/* for debugging purposes */ +static void +pefs_print_hash_table(struct hash_table *checksum_hash_tablep, uint8_t hash_len) +{ + struct file_header *fhp; + struct checksum *csp; + uint32_t i,j; + + printf("\n+++Printing Hash Table+++\n\n"); + for (i = 0; i < checksum_hash_tablep->size; i++) { + printf("\nbucket %d with elements: %u\n", i, checksum_hash_tablep->buckets[i].nelements); + LIST_FOREACH(fhp, &(checksum_hash_tablep->buckets[i].file_headers), bucket_entries) { + printf("\tid = %d!\tnhashes = %d\n", (int)fhp->file_id, fhp->nhashes); + TAILQ_FOREACH(csp, &(fhp->checksums), checksum_entries) { + printf("\t\tdigest="); + for (j = 0; j < hash_len; j++) + printf("%02x", csp->hash[j]); + printf("\n"); + } + } + } +} + +static int +pefs_read_checksum_file_header(int fdin, struct checksum_file_header *cfhp) +{ + uint32_t bytes, hash_table_size; + + bytes = read(fdin, &(cfhp->version), sizeof(cfhp->version)); + if (bytes != sizeof(cfhp->version)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + + bytes = read(fdin, &(cfhp->reserved), sizeof(cfhp->reserved)); + if (bytes != sizeof(cfhp->reserved)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + + bytes = read(fdin, &(cfhp->hash_len), sizeof(cfhp->hash_len)); + if (bytes != sizeof(cfhp->hash_len)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + + bytes = read(fdin, cfhp->hash_algo, sizeof(cfhp->hash_algo)); + if (bytes != sizeof(cfhp->hash_algo)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + + bytes = read(fdin, &(cfhp->offset_to_hash_table), sizeof(cfhp->offset_to_hash_table)); + if (bytes != sizeof(cfhp->offset_to_hash_table)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + + bytes = read(fdin, &hash_table_size, sizeof(hash_table_size)); + if (bytes != sizeof(hash_table_size)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + cfhp->hash_table_size = le32toh(hash_table_size); + + dprintf(("+++printing checksum file header info+++\n")); + dprintf(("version %X\nhash_len %d\nhash_algo %s\n", cfhp->version, cfhp->hash_len, cfhp->hash_algo)); + dprintf(("offset to hash table %d\nhash table size %d\n", cfhp->offset_to_hash_table, cfhp->hash_table_size)); + + return (0); +} + +static int +pefs_read_bucket(int fdin, struct bucket *bp, uint32_t *buckets_offset) +{ + uint32_t offset_to_chain, nelements; + int bytes; + + //dprintf(("bucket offset = %d\n", *buckets_offset)); + + bytes = pread(fdin, &offset_to_chain, sizeof(offset_to_chain), *buckets_offset); + if (bytes != sizeof(offset_to_chain)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + bp->offset_to_chain = le32toh(offset_to_chain); + (*buckets_offset)+= sizeof(offset_to_chain); + + bytes = pread(fdin, &nelements, sizeof(nelements), *buckets_offset); + if (bytes != sizeof(nelements)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + bp->nelements = le32toh(nelements); + (*buckets_offset)+= sizeof(nelements); + + //dprintf(("\n++priting bucket info++\n")); + //dprintf(("offset to chain %d\nnelements %d\n", bp->offset_to_chain, bp->nelements)); + + return (0); +} + +static int +pefs_read_file_header(int fdin, struct file_header *fhp, uint32_t *fh_offset) +{ + uint64_t file_id; + uint32_t nhashes, offset_to_checksums; + int bytes; + + bytes = pread(fdin, &nhashes, sizeof(nhashes), *fh_offset); + if (bytes != sizeof(nhashes)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + fhp->nhashes = le32toh(nhashes); + (*fh_offset)+= sizeof(nhashes); + + bytes = pread(fdin, &offset_to_checksums, sizeof(offset_to_checksums), *fh_offset); + if (bytes != sizeof(offset_to_checksums)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + fhp->offset_to_checksums = le32toh(offset_to_checksums); + (*fh_offset)+= sizeof(offset_to_checksums); + + bytes = pread(fdin, &file_id, sizeof(file_id), *fh_offset); + if (bytes != sizeof(file_id)) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + fhp->file_id = le64toh(file_id); + (*fh_offset)+= sizeof(file_id); + + //dprintf(("\nfile header offset = %d\n", *fh_offset)); + //dprintf(("\n++priting file header info++\n")); + //dprintf(("nhashes %d\noffset_to_checksums %d\n", fhp->nhashes, fhp->offset_to_checksums)); + //dprintf(("file id %d\n", (int)fhp->file_id)); + + return (0); +} + +static int +pefs_read_hash(int fdin, struct checksum *csp, uint32_t *hashes_offset, uint8_t hash_len) +{ + int bytes; + + bytes = pread(fdin, csp->hash, hash_len, *hashes_offset); + if (bytes != hash_len) { + perror("error reading from .pefs.checksum"); + return (ERROR); + } + (*hashes_offset)+= hash_len; + + //dprintf(("hashes offset = %d\n", *hashes_offset)); + //dprintf(("hash %s\n", csp->hash)); + + return (0); +} + +static int +pefs_read_checksum_file(int fdin, struct checksum_file_header *cfhp, struct hash_table *chtp) +{ + struct bucket *bp; + struct checksum *csp; + struct file_header *fhp; + uint32_t i, j, k, buckets_offset, fh_offset, hashes_offset; + int error; + + error = pefs_read_checksum_file_header(fdin, cfhp); + if (error != 0) + return (error); + + error = pefs_allocate_hash_table(chtp, cfhp->hash_table_size); + if (error != 0) + return (error); + + /* this points to where the buckets start */ + buckets_offset = cfhp->offset_to_hash_table; + + for (i = 0; i < chtp->size; i++) { + bp = &chtp->buckets[i]; + error = pefs_read_bucket(fdin, bp, &buckets_offset); + if (error != 0) + return (error); + + fh_offset = bp->offset_to_chain; + + for (j = 0; j < bp->nelements; j++) { + fhp = malloc(sizeof(struct file_header)); + if (fhp == NULL) { + perror("malloc"); + return (ERROR); + } + + error = pefs_read_file_header(fdin, fhp, &fh_offset); + if (error != 0) + return (ERROR); + + TAILQ_INIT(&(fhp->checksums)); + hashes_offset = fhp->offset_to_checksums; + pefs_add_to_bucket(bp, fhp); + + for (k = 0; k < fhp->nhashes; k++) { + csp = malloc(sizeof(struct checksum)); + if (csp == NULL) { + perror("malloc"); + return (ERROR); + } + csp->hash = malloc(cfhp->hash_len); + if (csp->hash == NULL) { + perror("malloc"); + return (ERROR); + } + + error = pefs_read_hash(fdin, csp, &hashes_offset, cfhp->hash_len); + if (error != 0) + return (error); + + pefs_add_to_file_header(fhp, csp); + } + } + } + + return (0); +} + +static void +usage(char *argv[]) +{ + printf("usage: %s /path/to/.pefs.checksum\n", argv[0]); +} + +/* + * XXXgpf: Purpose of code is to test validity of a .pefs.checksum file. + * Output from this program's pefs_print_hash_table() is checked against + * output from sbin/pefs' pefs_print_hash_table(). They should match. + * + */ +int +main(int argc, char *argv[]) +{ + char checksum_path[MAXPATHLEN]; + struct hash_table checksum_hash_table; + struct checksum_file_header cfh; + int error, fdin; + + if (argc != NARGS) { + usage(argv); + return (ERROR); + } + + strlcpy(checksum_path, argv[1], sizeof(checksum_path)); + fdin = open(checksum_path, O_RDONLY); + if (fdin == -1) { + perror("cannot open checksum file"); + return (ERROR); + } + + error = pefs_read_checksum_file(fdin, &cfh, &checksum_hash_table); + + /* this output should be the same as the one from sbin/pefs */ + pefs_print_hash_table(&checksum_hash_table, cfh.hash_len); + + close(fdin); + + return (error); +}