diff --git a/Makefile b/Makefile index c80c36c..bf07a30 100644 --- a/Makefile +++ b/Makefile @@ -22,22 +22,22 @@ CFLAGS ?= -O2 -Wall INSTALL ?= install PREFIX ?= /usr/local -# Disable multi threading. This will make the program smaller and a tiny -# bit easier on the system. It will make it slower in real time though, -# as we can't read from the harddisk and calculate hashes simultaneously. -#NO_THREADS = 1 +# Use multiple POSIX threads for calculating hashes. This should be slightly +# faster. Much faster on systems with multiple CPUs and fast harddrives. +#USE_PTHREADS = 1 -# Use the SHA1 implementation in the OpenSSL library +# Use the SHA1 implementation in the OpenSSL library instead of compiling our +# own. #USE_OPENSSL = 1 -# Disable support for long options. Will make the program smaller -# and perhaps even more portable. +# Disable support for long options. Will make the program smaller and perhaps +# even more portable. #NO_LONG_OPTIONS = 1 -# Disable a redundent check to see if the amount of bytes read from files -# while hashing matches the sum of reported file sizes. I've never seen -# this fail. It will fail if you change files yet to be hashed while -# mktorrent is running, but who'd want to do that? +# Disable a redundent check to see if the amount of bytes read from files while +# hashing matches the sum of reported file sizes. I've never seen this fail. It +# will fail if you change files yet to be hashed while mktorrent is running, +# but who'd want to do that? #NO_HASH_CHECK = 1 # Set the number of microseconds mktorrent will wait between every progress @@ -46,12 +46,12 @@ PREFIX ?= /usr/local #PROGRESS_PERIOD = 200000 # Maximum number of file descriptors mktorrent will open when scanning the -# directory. Default is 100, but I have no idea what a sane default -# for this value is, so your number is probably better. +# directory. Default is 100, but I have no idea what a sane default for this +# value is, so your number is probably better. #MAX_OPENFD = 100 -# Enable leftover debugging code. -# Usually just spams you with lots of useless information. +# Enable leftover debugging code. Usually just spams you with lots of useless +# information. #DEBUG = 1 @@ -65,10 +65,9 @@ SRCS := ftw.c init.c sha1.c hash.c output.c main.c OBJS = $(SRCS:.c=.o) LIBS := -ifdef NO_THREADS -DEFINES += -DNO_THREADS -SRCS := $(SRCS:hash.c=simple_hash.c) -else +ifdef USE_PTHREADS +DEFINES += -DUSE_PTHREADS +SRCS := $(SRCS:hash.c=hash_pthreads.c) LIBS += -lpthread endif diff --git a/hash.c b/hash.c index 82d365d..ed77b1c 100644 --- a/hash.c +++ b/hash.c @@ -17,199 +17,63 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef ALLINONE -#include /* exit(), malloc() */ + +#include /* exit() */ #include /* errno */ #include /* strerror() */ #include /* printf() etc. */ #include /* open() */ -#include /* access(), read(), close() */ +#include /* read(), close() */ + #ifdef USE_OPENSSL #include /* SHA1() - remember to compile with -lssl */ #else #include #include "sha1.h" #endif -#include /* pthread functions and data structures */ #include "mktorrent.h" #define EXPORT #endif /* ALLINONE */ - -#ifndef PROGRESS_PERIOD -#define PROGRESS_PERIOD 200000 -#endif - -struct piece_s; -typedef struct piece_s piece_t; -struct piece_s { - piece_t *next; - unsigned char *dest; - unsigned long len; - unsigned char data[1]; -}; - -struct queue_s; -typedef struct queue_s queue_t; -struct queue_s { - piece_t *free; - piece_t *full; - unsigned int buffers_max; - unsigned int buffers; - pthread_mutex_t mutex_free; - pthread_mutex_t mutex_full; - pthread_cond_t cond_empty; - pthread_cond_t cond_full; - unsigned int done; - unsigned int pieces; - unsigned int pieces_hashed; -}; - -static piece_t *get_free(queue_t *q, size_t piece_length) -{ - piece_t *r; - - pthread_mutex_lock(&q->mutex_free); - if (q->free) { - r = q->free; - q->free = r->next; - } else if (q->buffers < q->buffers_max) { - r = malloc(sizeof(piece_t) + piece_length - 1); - if (r == NULL) { - fprintf(stderr, "Out of memory.\n"); - exit(EXIT_FAILURE); - } - - q->buffers++; - } else { - while (q->free == NULL) { - pthread_cond_wait(&q->cond_full, &q->mutex_free); - } - - r = q->free; - q->free = r->next; - } - pthread_mutex_unlock(&q->mutex_free); - - return r; -} - -static piece_t *get_full(queue_t *q) -{ - piece_t *r; - - pthread_mutex_lock(&q->mutex_full); -again: - if (q->full) { - r = q->full; - q->full = r->next; - } else if (q->done) { - r = NULL; - } else { - pthread_cond_wait(&q->cond_empty, &q->mutex_full); - goto again; - } - pthread_mutex_unlock(&q->mutex_full); - - return r; -} - -static void put_free(queue_t *q, piece_t *p) -{ - pthread_mutex_lock(&q->mutex_free); - p->next = q->free; - q->free = p; - q->pieces_hashed++; - pthread_mutex_unlock(&q->mutex_free); - pthread_cond_signal(&q->cond_full); -} - -static void put_full(queue_t *q, piece_t *p) -{ - pthread_mutex_lock(&q->mutex_full); - p->next = q->full; - q->full = p; - pthread_mutex_unlock(&q->mutex_full); - pthread_cond_signal(&q->cond_empty); -} - -static void set_done(queue_t *q) -{ - pthread_mutex_lock(&q->mutex_full); - q->done = 1; - pthread_mutex_unlock(&q->mutex_full); - pthread_cond_broadcast(&q->cond_empty); -} - -static void free_buffers(queue_t *q) -{ - piece_t *first = q->free; - - while (first) { - piece_t *p = first; - first = p->next; - free(p); - } - - q->free = NULL; -} - /* - * print the progress in a thread of its own + * go through the files in file_list, split their contents into pieces + * of size piece_length and create the hash string, which is the + * concatenation of the (20 byte) SHA1 hash of every piece + * last piece may be shorter */ -static void *print_progress(void *data) +EXPORT unsigned char *make_hash() { - queue_t *q = data; - int err; - - err = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - if (err) { - fprintf(stderr, "Error setting thread cancel type: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - while (1) { - /* print progress and flush the buffer immediately */ - printf("\rHashed %u of %u pieces.", q->pieces_hashed, q->pieces); - fflush(stdout); - /* now sleep for PROGRESS_PERIOD microseconds */ - usleep(PROGRESS_PERIOD); - } - - return NULL; -} + fl_node f; /* pointer to a place in the file list */ + unsigned char *hash_string; /* the hash string */ + unsigned char *pos; /* position in the hash string */ + unsigned char *read_buf; /* read buffer */ + int fd; /* file descriptor */ + ssize_t r; /* number of bytes read from file(s) into + the read buffer */ + SHA_CTX c; /* SHA1 hashing context */ +#ifndef NO_HASH_CHECK + unsigned long long counter = 0; /* number of bytes hashed + should match size when done */ +#endif -static void *worker(void *data) -{ - queue_t *q = data; - piece_t *p; - SHA_CTX c; + /* allocate memory for the hash string + every SHA1 hash is SHA_DIGEST_LENGTH (20) bytes long */ + hash_string = malloc(pieces * SHA_DIGEST_LENGTH); + /* allocate memory for the read buffer to store 1 piece */ + read_buf = malloc(piece_length); - while ((p = get_full(q))) { - SHA1_Init(&c); - SHA1_Update(&c, p->data, p->len); - SHA1_Final(p->dest, &c); - put_free(q, p); + /* check if we've run out of memory */ + if (hash_string == NULL || read_buf == NULL) { + fprintf(stderr, "Out of memory.\n"); + exit(EXIT_FAILURE); } - return NULL; -} - -static void read_files(queue_t *q, unsigned char *pos) -{ - int fd; /* file descriptor */ - fl_node f; /* pointer to a place in the file - list */ - ssize_t r = 0; /* number of bytes read from - file(s) into the read buffer */ -#ifndef NO_HASH_CHECK - unsigned long long counter = 0; /* number of bytes hashed - should match size when done */ -#endif - piece_t *p = get_free(q, piece_length); - + /* initiate pos to point to the beginning of hash_string */ + pos = hash_string; + /* and initiate r to 0 since we haven't read anything yet */ + r = 0; /* go through all the files in the file list */ for (f = file_list; f; f = f->next) { @@ -219,9 +83,15 @@ static void read_files(queue_t *q, unsigned char *pos) f->path, strerror(errno)); exit(EXIT_FAILURE); } + printf("Hashing %s.\n", f->path); + fflush(stdout); + /* fill the read buffer with the contents of the file and append + the SHA1 hash of it to the hash string when the buffer is full. + repeat until we can't fill the read buffer and we've thus come + to the end of the file */ while (1) { - ssize_t d = read(fd, p->data + r, piece_length - r); + ssize_t d = read(fd, read_buf + r, piece_length - r); if (d < 0) { fprintf(stderr, "Error reading from '%s': %s\n", @@ -234,15 +104,14 @@ static void read_files(queue_t *q, unsigned char *pos) if (r < piece_length) break; - p->dest = pos; - p->len = piece_length; - put_full(q, p); + SHA1_Init(&c); + SHA1_Update(&c, read_buf, piece_length); + SHA1_Final(pos, &c); pos += SHA_DIGEST_LENGTH; #ifndef NO_HASH_CHECK - counter += r; + counter += r; /* r == piece_length */ #endif r = 0; - p = get_free(q, piece_length); } /* now close the file */ @@ -254,9 +123,9 @@ static void read_files(queue_t *q, unsigned char *pos) } /* finally append the hash of the last irregular piece to the hash string */ - p->dest = pos; - p->len = r; - put_full(q, p); + SHA1_Init(&c); + SHA1_Update(&c, read_buf, r); + SHA1_Final(pos, &c); #ifndef NO_HASH_CHECK counter += r; @@ -266,93 +135,9 @@ static void read_files(queue_t *q, unsigned char *pos) exit(EXIT_FAILURE); } #endif -} - -EXPORT unsigned char *make_hash() -{ - queue_t q = { - NULL, NULL, 0, 0, - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_COND_INITIALIZER, - PTHREAD_COND_INITIALIZER, - 0, 0, 0 - }; - pthread_t print_progress_thread; /* progress printer thread */ - pthread_t *workers; - unsigned char *hash_string; /* the hash string */ - unsigned int i; - int err; - - workers = alloca(threads * sizeof(pthread_t)); - hash_string = malloc(pieces * SHA_DIGEST_LENGTH); - if (workers == NULL || hash_string == NULL) - return NULL; - - q.pieces = pieces; - q.buffers_max = 3*threads; - - /* create worker threads */ - for (i = 0; i < threads; i++) { - err = pthread_create(&workers[i], NULL, worker, &q); - if (err) { - fprintf(stderr, "Error creating thread: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - } - - /* now set off the progress printer */ - err = pthread_create(&print_progress_thread, NULL, print_progress, &q); - if (err) { - fprintf(stderr, "Error creating thread: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - /* read files and feed pieces to the workers */ - read_files(&q, hash_string); - - /* we're done so stop printing our progress. */ - err = pthread_cancel(print_progress_thread); - if (err) { - fprintf(stderr, "Error cancelling thread: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - /* inform workers we're done */ - set_done(&q); - - /* wait for workers to finish */ - for (i = 0; i < threads; i++) { - err = pthread_join(workers[i], NULL); - if (err) { - fprintf(stderr, "Error joining thread: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - } - - /* the progress printer should be done by now too */ - err = pthread_join(print_progress_thread, NULL); - if (err) { - fprintf(stderr, "Error joining thread: %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - /* destroy mutexes and condition variables */ - pthread_mutex_destroy(&q.mutex_full); - pthread_mutex_destroy(&q.mutex_free); - pthread_cond_destroy(&q.cond_empty); - pthread_cond_destroy(&q.cond_full); - - /* free buffers */ - free_buffers(&q); - /* ok, let the user know we're done too */ - printf("\rHashed %u of %u pieces.\n", q.pieces_hashed, q.pieces); + /* free the read buffer before we return */ + free(read_buf); return hash_string; } diff --git a/hash_pthreads.c b/hash_pthreads.c new file mode 100644 index 0000000..82d365d --- /dev/null +++ b/hash_pthreads.c @@ -0,0 +1,358 @@ +/* +This file is part of mktorrent +Copyright (C) 2007, 2009 Emil Renner Berthing + +mktorrent is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +mktorrent is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ +#ifndef ALLINONE +#include /* exit(), malloc() */ +#include /* errno */ +#include /* strerror() */ +#include /* printf() etc. */ +#include /* open() */ +#include /* access(), read(), close() */ +#ifdef USE_OPENSSL +#include /* SHA1() - remember to compile with -lssl */ +#else +#include +#include "sha1.h" +#endif +#include /* pthread functions and data structures */ + +#include "mktorrent.h" + +#define EXPORT +#endif /* ALLINONE */ + + +#ifndef PROGRESS_PERIOD +#define PROGRESS_PERIOD 200000 +#endif + +struct piece_s; +typedef struct piece_s piece_t; +struct piece_s { + piece_t *next; + unsigned char *dest; + unsigned long len; + unsigned char data[1]; +}; + +struct queue_s; +typedef struct queue_s queue_t; +struct queue_s { + piece_t *free; + piece_t *full; + unsigned int buffers_max; + unsigned int buffers; + pthread_mutex_t mutex_free; + pthread_mutex_t mutex_full; + pthread_cond_t cond_empty; + pthread_cond_t cond_full; + unsigned int done; + unsigned int pieces; + unsigned int pieces_hashed; +}; + +static piece_t *get_free(queue_t *q, size_t piece_length) +{ + piece_t *r; + + pthread_mutex_lock(&q->mutex_free); + if (q->free) { + r = q->free; + q->free = r->next; + } else if (q->buffers < q->buffers_max) { + r = malloc(sizeof(piece_t) + piece_length - 1); + if (r == NULL) { + fprintf(stderr, "Out of memory.\n"); + exit(EXIT_FAILURE); + } + + q->buffers++; + } else { + while (q->free == NULL) { + pthread_cond_wait(&q->cond_full, &q->mutex_free); + } + + r = q->free; + q->free = r->next; + } + pthread_mutex_unlock(&q->mutex_free); + + return r; +} + +static piece_t *get_full(queue_t *q) +{ + piece_t *r; + + pthread_mutex_lock(&q->mutex_full); +again: + if (q->full) { + r = q->full; + q->full = r->next; + } else if (q->done) { + r = NULL; + } else { + pthread_cond_wait(&q->cond_empty, &q->mutex_full); + goto again; + } + pthread_mutex_unlock(&q->mutex_full); + + return r; +} + +static void put_free(queue_t *q, piece_t *p) +{ + pthread_mutex_lock(&q->mutex_free); + p->next = q->free; + q->free = p; + q->pieces_hashed++; + pthread_mutex_unlock(&q->mutex_free); + pthread_cond_signal(&q->cond_full); +} + +static void put_full(queue_t *q, piece_t *p) +{ + pthread_mutex_lock(&q->mutex_full); + p->next = q->full; + q->full = p; + pthread_mutex_unlock(&q->mutex_full); + pthread_cond_signal(&q->cond_empty); +} + +static void set_done(queue_t *q) +{ + pthread_mutex_lock(&q->mutex_full); + q->done = 1; + pthread_mutex_unlock(&q->mutex_full); + pthread_cond_broadcast(&q->cond_empty); +} + +static void free_buffers(queue_t *q) +{ + piece_t *first = q->free; + + while (first) { + piece_t *p = first; + first = p->next; + free(p); + } + + q->free = NULL; +} + +/* + * print the progress in a thread of its own + */ +static void *print_progress(void *data) +{ + queue_t *q = data; + int err; + + err = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (err) { + fprintf(stderr, "Error setting thread cancel type: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + + while (1) { + /* print progress and flush the buffer immediately */ + printf("\rHashed %u of %u pieces.", q->pieces_hashed, q->pieces); + fflush(stdout); + /* now sleep for PROGRESS_PERIOD microseconds */ + usleep(PROGRESS_PERIOD); + } + + return NULL; +} + +static void *worker(void *data) +{ + queue_t *q = data; + piece_t *p; + SHA_CTX c; + + while ((p = get_full(q))) { + SHA1_Init(&c); + SHA1_Update(&c, p->data, p->len); + SHA1_Final(p->dest, &c); + put_free(q, p); + } + + return NULL; +} + +static void read_files(queue_t *q, unsigned char *pos) +{ + int fd; /* file descriptor */ + fl_node f; /* pointer to a place in the file + list */ + ssize_t r = 0; /* number of bytes read from + file(s) into the read buffer */ +#ifndef NO_HASH_CHECK + unsigned long long counter = 0; /* number of bytes hashed + should match size when done */ +#endif + piece_t *p = get_free(q, piece_length); + + /* go through all the files in the file list */ + for (f = file_list; f; f = f->next) { + + /* open the current file for reading */ + if ((fd = open(f->path, O_RDONLY)) == -1) { + fprintf(stderr, "Error opening '%s' for reading: %s\n", + f->path, strerror(errno)); + exit(EXIT_FAILURE); + } + + while (1) { + ssize_t d = read(fd, p->data + r, piece_length - r); + + if (d < 0) { + fprintf(stderr, "Error reading from '%s': %s\n", + f->path, strerror(errno)); + exit(EXIT_FAILURE); + } + + r += d; + + if (r < piece_length) + break; + + p->dest = pos; + p->len = piece_length; + put_full(q, p); + pos += SHA_DIGEST_LENGTH; +#ifndef NO_HASH_CHECK + counter += r; +#endif + r = 0; + p = get_free(q, piece_length); + } + + /* now close the file */ + if (close(fd)) { + fprintf(stderr, "Error closing '%s': %s\n", + f->path, strerror(errno)); + exit(EXIT_FAILURE); + } + } + + /* finally append the hash of the last irregular piece to the hash string */ + p->dest = pos; + p->len = r; + put_full(q, p); + +#ifndef NO_HASH_CHECK + counter += r; + if (counter != size) { + fprintf(stderr, "Counted %llu bytes, but hashed %llu bytes. " + "Something is wrong...\n", size, counter); + exit(EXIT_FAILURE); + } +#endif +} + +EXPORT unsigned char *make_hash() +{ + queue_t q = { + NULL, NULL, 0, 0, + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_COND_INITIALIZER, + PTHREAD_COND_INITIALIZER, + 0, 0, 0 + }; + pthread_t print_progress_thread; /* progress printer thread */ + pthread_t *workers; + unsigned char *hash_string; /* the hash string */ + unsigned int i; + int err; + + workers = alloca(threads * sizeof(pthread_t)); + hash_string = malloc(pieces * SHA_DIGEST_LENGTH); + if (workers == NULL || hash_string == NULL) + return NULL; + + q.pieces = pieces; + q.buffers_max = 3*threads; + + /* create worker threads */ + for (i = 0; i < threads; i++) { + err = pthread_create(&workers[i], NULL, worker, &q); + if (err) { + fprintf(stderr, "Error creating thread: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + } + + /* now set off the progress printer */ + err = pthread_create(&print_progress_thread, NULL, print_progress, &q); + if (err) { + fprintf(stderr, "Error creating thread: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + + /* read files and feed pieces to the workers */ + read_files(&q, hash_string); + + /* we're done so stop printing our progress. */ + err = pthread_cancel(print_progress_thread); + if (err) { + fprintf(stderr, "Error cancelling thread: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + + /* inform workers we're done */ + set_done(&q); + + /* wait for workers to finish */ + for (i = 0; i < threads; i++) { + err = pthread_join(workers[i], NULL); + if (err) { + fprintf(stderr, "Error joining thread: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + } + + /* the progress printer should be done by now too */ + err = pthread_join(print_progress_thread, NULL); + if (err) { + fprintf(stderr, "Error joining thread: %s\n", + strerror(err)); + exit(EXIT_FAILURE); + } + + /* destroy mutexes and condition variables */ + pthread_mutex_destroy(&q.mutex_full); + pthread_mutex_destroy(&q.mutex_free); + pthread_cond_destroy(&q.cond_empty); + pthread_cond_destroy(&q.cond_full); + + /* free buffers */ + free_buffers(&q); + + /* ok, let the user know we're done too */ + printf("\rHashed %u of %u pieces.\n", q.pieces_hashed, q.pieces); + + return hash_string; +} diff --git a/init.c b/init.c index 079a248..6b5b543 100644 --- a/init.c +++ b/init.c @@ -312,7 +312,7 @@ static void print_help() "-o, --output= : set the path and filename of the created file\n" " default is .torrent\n" "-p, --private : set the private flag\n" -#ifndef NO_THREADS +#ifdef USE_PTHREADS "-t, --threads= : use threads for calculating hashes\n" " default is 2\n" #endif @@ -337,7 +337,7 @@ static void print_help() "-o : set the path and filename of the created file\n" " default is .torrent\n" "-p : set the private flag\n" -#ifndef NO_THREADS +#ifdef USE_PTHREADS "-t : use threads for calculating hashes\n" " default is 2\n" #endif @@ -407,7 +407,6 @@ EXPORT void init(int argc, char *argv[]) { int c; /* return value of getopt() */ al_node announce_last = NULL; - #ifndef NO_LONG_OPTIONS /* the option structure to pass to getopt_long() */ static struct option long_options[] = { @@ -419,7 +418,7 @@ EXPORT void init(int argc, char *argv[]) {"name", 1, NULL, 'n'}, {"output", 1, NULL, 'o'}, {"private", 0, NULL, 'p'}, -#ifndef NO_THREADS +#ifdef USE_PTHREADS {"threads", 1, NULL, 't'}, #endif {"verbose", 0, NULL, 'v'}, @@ -428,22 +427,20 @@ EXPORT void init(int argc, char *argv[]) }; #endif - /* now parse the command line options given */ -#ifndef NO_LONG_OPTIONS -#ifdef NO_THREADS - while ((c = getopt_long(argc, argv, "a:c:dhl:n:o:pvw:", - long_options, NULL)) != -1) { +#ifdef USE_PTHREADS +#define OPT_STRING "a:c:dhl:n:o:pt:vw:" #else - while ((c = getopt_long(argc, argv, "a:c:dhl:n:o:pt:vw:", - long_options, NULL)) != -1) { +#define OPT_STRING "a:c:dhl:n:o:pvw:" #endif + +#ifdef NO_LONG_OPTIONS + /* now parse the command line options given */ + while ((c = getopt(argc, argv, OPT_STRING)) != -1) { #else -#ifdef NO_THREADS - while ((c = getopt(argc, argv, "a:c:dhl:n:o:pvw:")) != -1) { -#else - while ((c = getopt(argc, argv, "a:c:dhl:n:o:pt:vw:")) != -1) { -#endif + while ((c = getopt_long(argc, argv, OPT_STRING, + long_options, NULL)) != -1) { #endif +#undef OPT_STRING switch (c) { case 'a': if (announce_last == NULL) { @@ -482,7 +479,7 @@ EXPORT void init(int argc, char *argv[]) case 'p': private = 1; break; -#ifndef NO_THREADS +#ifdef USE_PTHREADS case 't': threads = atoi(optarg); break; @@ -525,7 +522,7 @@ EXPORT void init(int argc, char *argv[]) exit(EXIT_FAILURE); } -#ifndef NO_THREADS +#ifdef USE_PTHREADS /* check the number of threads */ if (threads < 1 || threads > 20) { fprintf(stderr, "The number of threads must be a number" diff --git a/main.c b/main.c index 59c35a2..a43bbfa 100644 --- a/main.c +++ b/main.c @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include /* access(), read(), close(), getcwd() */ #ifndef NO_LONG_OPTIONS #include /* getopt_long() */ -#endif /* NO_LONG_OPTIONS */ +#endif #include /* time() */ #include /* opendir(), closedir(), readdir() etc. */ #ifdef USE_OPENSSL @@ -38,12 +38,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #else #include #endif -#ifndef NO_THREADS +#ifdef USE_PTHREADS #include /* pthread functions and data structures */ -#endif /* NO_THREADS */ +#endif #define EXPORT static #else + #define EXPORT #endif /* ALLINONE */ @@ -69,7 +70,7 @@ EXPORT unsigned long long size = 0; /* the combined size of all files EXPORT fl_node file_list = NULL; /* linked list of files and their individual sizes */ EXPORT unsigned int pieces; /* number of pieces */ -#ifndef NO_THREADS +#ifdef USE_PTHREADS EXPORT unsigned int threads = 2; /* number of threads used for hashing */ #endif @@ -81,11 +82,11 @@ EXPORT unsigned int threads = 2; /* number of threads used for hashing */ #include "sha1.c" #endif -#ifdef NO_THREADS -#include "simple_hash.c" +#ifdef USE_PTHREADS +#include "hash_pthreads.c" #else #include "hash.c" -#endif /* NO_THREADS */ +#endif #include "output.c" #else diff --git a/mktorrent.h b/mktorrent.h index 97c118f..bb378f8 100644 --- a/mktorrent.h +++ b/mktorrent.h @@ -53,7 +53,7 @@ extern int verbose; /* be verbose */ extern unsigned long long size; /* combined size of all files in the torrent */ extern fl_node file_list; /* list of files and their individual sizes */ extern unsigned int pieces; /* number of pieces */ -#ifndef NO_THREADS +#ifdef USE_PTHREADS extern unsigned int threads; /* number of threads used for hashing */ #endif diff --git a/sha1.c b/sha1.c index 1979773..fc939f5 100644 --- a/sha1.c +++ b/sha1.c @@ -198,7 +198,7 @@ EXPORT void SHA1_Final(uint8_t *digest, SHA_CTX *context) memset(finalcount, 0, 8); #endif -#ifdef SHA1_HANDSOFF /* make SHA1Transform overwrite its own static vars */ +#ifdef SHA1_HANDSOFF /* make SHA1Transform overwrite its own static vars */ SHA1_Transform(context->state, context->buffer); #endif } diff --git a/simple_hash.c b/simple_hash.c deleted file mode 100644 index ed77b1c..0000000 --- a/simple_hash.c +++ /dev/null @@ -1,143 +0,0 @@ -/* -This file is part of mktorrent -Copyright (C) 2007, 2009 Emil Renner Berthing - -mktorrent is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -mktorrent is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/ -#ifndef ALLINONE - -#include /* exit() */ -#include /* errno */ -#include /* strerror() */ -#include /* printf() etc. */ -#include /* open() */ -#include /* read(), close() */ - -#ifdef USE_OPENSSL -#include /* SHA1() - remember to compile with -lssl */ -#else -#include -#include "sha1.h" -#endif - -#include "mktorrent.h" - -#define EXPORT -#endif /* ALLINONE */ - -/* - * go through the files in file_list, split their contents into pieces - * of size piece_length and create the hash string, which is the - * concatenation of the (20 byte) SHA1 hash of every piece - * last piece may be shorter - */ -EXPORT unsigned char *make_hash() -{ - fl_node f; /* pointer to a place in the file list */ - unsigned char *hash_string; /* the hash string */ - unsigned char *pos; /* position in the hash string */ - unsigned char *read_buf; /* read buffer */ - int fd; /* file descriptor */ - ssize_t r; /* number of bytes read from file(s) into - the read buffer */ - SHA_CTX c; /* SHA1 hashing context */ -#ifndef NO_HASH_CHECK - unsigned long long counter = 0; /* number of bytes hashed - should match size when done */ -#endif - - /* allocate memory for the hash string - every SHA1 hash is SHA_DIGEST_LENGTH (20) bytes long */ - hash_string = malloc(pieces * SHA_DIGEST_LENGTH); - /* allocate memory for the read buffer to store 1 piece */ - read_buf = malloc(piece_length); - - /* check if we've run out of memory */ - if (hash_string == NULL || read_buf == NULL) { - fprintf(stderr, "Out of memory.\n"); - exit(EXIT_FAILURE); - } - - /* initiate pos to point to the beginning of hash_string */ - pos = hash_string; - /* and initiate r to 0 since we haven't read anything yet */ - r = 0; - /* go through all the files in the file list */ - for (f = file_list; f; f = f->next) { - - /* open the current file for reading */ - if ((fd = open(f->path, O_RDONLY)) == -1) { - fprintf(stderr, "Error opening '%s' for reading: %s\n", - f->path, strerror(errno)); - exit(EXIT_FAILURE); - } - printf("Hashing %s.\n", f->path); - fflush(stdout); - - /* fill the read buffer with the contents of the file and append - the SHA1 hash of it to the hash string when the buffer is full. - repeat until we can't fill the read buffer and we've thus come - to the end of the file */ - while (1) { - ssize_t d = read(fd, read_buf + r, piece_length - r); - - if (d < 0) { - fprintf(stderr, "Error reading from '%s': %s\n", - f->path, strerror(errno)); - exit(EXIT_FAILURE); - } - - r += d; - - if (r < piece_length) - break; - - SHA1_Init(&c); - SHA1_Update(&c, read_buf, piece_length); - SHA1_Final(pos, &c); - pos += SHA_DIGEST_LENGTH; -#ifndef NO_HASH_CHECK - counter += r; /* r == piece_length */ -#endif - r = 0; - } - - /* now close the file */ - if (close(fd)) { - fprintf(stderr, "Error closing '%s': %s\n", - f->path, strerror(errno)); - exit(EXIT_FAILURE); - } - } - - /* finally append the hash of the last irregular piece to the hash string */ - SHA1_Init(&c); - SHA1_Update(&c, read_buf, r); - SHA1_Final(pos, &c); - -#ifndef NO_HASH_CHECK - counter += r; - if (counter != size) { - fprintf(stderr, "Counted %llu bytes, but hashed %llu bytes. " - "Something is wrong...\n", size, counter); - exit(EXIT_FAILURE); - } -#endif - - /* free the read buffer before we return */ - free(read_buf); - - return hash_string; -}