diff -Naur gnut-0.4.25/AUTHORS gnut-0.4.25-ps0/AUTHORS --- gnut-0.4.25/AUTHORS Wed Jun 27 11:52:08 2001 +++ gnut-0.4.25-ps0/AUTHORS Mon Jul 2 11:39:14 2001 @@ -18,7 +18,7 @@ LT1 Linards Ticmanis MK1 Matthias Kramm PD1 Paul Duncan (formerly and ) - PS1 Peter Selinger + PS1 Peter Selinger RB1 Rick Bunke RJ1 Ray Jones RPM Robert Munafo diff -Naur gnut-0.4.25/ChangeLog gnut-0.4.25-ps0/ChangeLog --- gnut-0.4.25/ChangeLog Wed Jun 27 11:52:08 2001 +++ gnut-0.4.25-ps0/ChangeLog Mon Jul 2 11:41:23 2001 @@ -9,6 +9,9 @@ v0.4.26 (not yet released) +v0.4.25-ps0 2001.07.02 + (0702) PS1 - Migrated Peter Selinger's patches to version 0.4.25 + v0.4.25 2001.06.27 (0627) RPM - DR1's optimizations disabled because of major SEGFAULT problem when the file cache (cache_path, etc.) is turned on. In the @@ -75,6 +78,9 @@ that are on hosts that returned more than one match to a single search. +v0.4.21-ps0 2001.04.12 + (0412) PS1 - Migrated Peter Selinger's patches to version 0.4.21 + v0.4.21 2001.03.28 (0316) RPM - Stop counting dropped DOS PINGs against a connection's "duplicate" count. This reduces the turnover rate in the connection @@ -94,6 +100,13 @@ (0212) RPM - Adding documentation explaining how to change anything (including the ./configure script or a Makefile) and actually get the changes to take effect. Not done yet. + +v0.4.20-ps-0 2001.03.26 + (0122) PS1 - Human readable formal for transfer_log + (0122) PS1 - Fixed HTTP subrange bug + (0121) PS1 - List titles in alphabetical order + (0117) PS1 - Changed slash-stripping code to leave "/" untouched + (0117) PS1 - Rewrote directory scanning code in C, removing dependency on GNU "find" or Perl v0.4.20 2001.02.07 (0124) RPM - A search for "john john" will now match only those files diff -Naur gnut-0.4.25/Makefile.am gnut-0.4.25-ps0/Makefile.am --- gnut-0.4.25/Makefile.am Fri May 5 13:14:35 2000 +++ gnut-0.4.25-ps0/Makefile.am Mon Jul 2 12:26:36 2001 @@ -2,4 +2,4 @@ EXTRA_DIST = \ README COPYING AUTHORS INSTALL TODO \ - gnut.glade gnutrc.sample wgnut.dsp wgnut.dsw + gnut.glade gnutrc.sample wgnut.dsp wgnut.dsw ac DEPEND conf-real dmk fp mk GDJ HACKING diff -Naur gnut-0.4.25/Makefile.in gnut-0.4.25-ps0/Makefile.in --- gnut-0.4.25/Makefile.in Wed Jun 27 11:53:05 2001 +++ gnut-0.4.25-ps0/Makefile.in Mon Jul 2 12:26:58 2001 @@ -70,7 +70,7 @@ SUBDIRS = src macros doc -EXTRA_DIST = README COPYING AUTHORS INSTALL TODO gnut.glade gnutrc.sample wgnut.dsp wgnut.dsw +EXTRA_DIST = README COPYING AUTHORS INSTALL TODO gnut.glade gnutrc.sample wgnut.dsp wgnut.dsw ac DEPEND conf-real dmk fp mk GDJ HACKING ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs diff -Naur gnut-0.4.25/conf-real gnut-0.4.25-ps0/conf-real --- gnut-0.4.25/conf-real Wed Jun 27 11:52:32 2001 +++ gnut-0.4.25-ps0/conf-real Mon Jul 2 11:39:36 2001 @@ -705,7 +705,7 @@ PACKAGE=gnut -VERSION=0.4.25 +VERSION=0.4.25-ps0 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } diff -Naur gnut-0.4.25/configure.in gnut-0.4.25-ps0/configure.in --- gnut-0.4.25/configure.in Fri Jun 8 12:34:14 2001 +++ gnut-0.4.25-ps0/configure.in Mon Jul 2 11:39:59 2001 @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(src/gnut.c) -AM_INIT_AUTOMAKE(gnut,0.4.25) +AM_INIT_AUTOMAKE(gnut,0.4.25-ps0) AM_MAINTAINER_MODE AM_ACLOCAL_INCLUDE(macros) diff -Naur gnut-0.4.25/mkinstalldirs gnut-0.4.25-ps0/mkinstalldirs --- gnut-0.4.25/mkinstalldirs Tue Oct 26 00:51:30 1999 +++ gnut-0.4.25-ps0/mkinstalldirs Mon Jul 2 11:36:25 2001 @@ -4,7 +4,7 @@ # Created: 1993-05-16 # Public domain -# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ +# $Id: mkinstalldirs,v 1.1.1.1 2001/03/26 19:58:49 selinger Exp $ errstatus=0 diff -Naur gnut-0.4.25/src/http.c gnut-0.4.25-ps0/src/http.c --- gnut-0.4.25/src/http.c Thu Jun 7 14:21:32 2001 +++ gnut-0.4.25-ps0/src/http.c Mon Jul 2 12:30:11 2001 @@ -790,7 +790,7 @@ if (gt->fsock<0) { gd_s(GNUT_HTTP_DEBUG,"couldn't open something!\n"); - if (gt->fsock >= 0) { + if (gt->fsock >= 0) { /* not reachable ? */ close_s(gt->fsock); } fre_str(&buf, 175); @@ -845,10 +845,15 @@ gnut_transfer_loop(gt, 0, 0, 0); if (gc_transferlog) { - fprintf(gc_transferlog, "%d\ts\t%i.%i.%i.%i:%i\t%d\t%d\t%d\t%s\n", - (int) time(0), gt->ip[0], gt->ip[1], gt->ip[2], gt->ip[3], - gt->port, gt->bytes, gt->total, gt->rate_bytes >> 4L, - gt->fname); + time_t t = time(0); + char *timestr = ctime(&t); + char *nl = strchr(timestr, '\n'); + + if (nl) *nl = 0; + fprintf(gc_transferlog, "S %s %i.%i.%i.%i:%i \"%s\" %d/%d @ %sbps\n", + timestr, gt->ip[0], gt->ip[1], gt->ip[2], gt->ip[3], + gt->port, si->path, gt->bytes, gt->total, + munge_bytes(gt->rate_bytes >> 4L)); } gd_s(GNUT_HTTP_DEBUG,"closing up transfer\n"); @@ -1189,7 +1194,9 @@ hdr = list->data; if (!hdr) break; - if (!strcmp(hdr->name, name)) { + /* according to the HTTP specification, HTTP header field + names are case insensitive. Thus we use strcasecmp. -PS */ + if (!strcasecmp(hdr->name, name)) { gd_s(HTTP_REQUEST_DEBUG, "http_request_find_header OUT - found header "); gd_s(HTTP_REQUEST_DEBUG, hdr->value); gd_s(HTTP_REQUEST_DEBUG, "\n"); diff -Naur gnut-0.4.25/src/lib.c gnut-0.4.25-ps0/src/lib.c --- gnut-0.4.25/src/lib.c Mon Jun 11 19:48:39 2001 +++ gnut-0.4.25-ps0/src/lib.c Mon Jul 2 11:52:56 2001 @@ -891,9 +891,7 @@ char *s; for(s=str; *s; s++) { - if ((*s >= 'A') && (*s <= 'Z')) { - *s = (*s) + 'a' - 'A'; - } + *s = tolower(*s); } } diff -Naur gnut-0.4.25/src/lib.h gnut-0.4.25-ps0/src/lib.h --- gnut-0.4.25/src/lib.h Thu Jun 14 18:34:55 2001 +++ gnut-0.4.25-ps0/src/lib.h Mon Jul 2 11:49:40 2001 @@ -7,7 +7,7 @@ #define GNUT_LIB_H 0 #ifdef WIN32 -# define VERSION "0.4.25/win32" +# define VERSION "0.4.25-ps0/win32" #endif /* Highest used bugnum so far: 538 */ diff -Naur gnut-0.4.25/src/list.c gnut-0.4.25-ps0/src/list.c --- gnut-0.4.25/src/list.c Wed May 16 16:28:26 2001 +++ gnut-0.4.25-ps0/src/list.c Mon Jul 2 11:36:48 2001 @@ -171,6 +171,29 @@ } } +/* Gnut_List * gnut_list_insert_ordered(Gnut_List *list,void *data,int (*cmp)(void *, void *)) + * + * inserts data into the ordered linked list list. Here cmp is a comparison + * function for list items, returning -1, 0, or 1 like strcmp. + * returns the new head pointer into the list */ +Gnut_List * gnut_list_insert_ordered(Gnut_List *list,void *data,int (*cmp)(void *, void *)) +{ + Gnut_List **link; + Gnut_List *glnew; + + glnew = (Gnut_List *) xmalloc(sizeof(Gnut_List)); + assert(glnew); + glnew->data = data; + + for (link = &list; *link != NULL; link = &((*link)->next)) { + if ((*cmp)(data, (*link)->data)<=0) + break; + } + glnew->next = *link; + *link = glnew; + return list; +} + /* Gnut_List * gnut_list_next(Gnut_List *list) * * convenience function to return next item in list */ diff -Naur gnut-0.4.25/src/list.h gnut-0.4.25-ps0/src/list.h --- gnut-0.4.25/src/list.h Fri Apr 20 17:20:28 2001 +++ gnut-0.4.25-ps0/src/list.h Mon Jul 2 11:51:02 2001 @@ -21,6 +21,7 @@ Gnut_List * gnut_list_prepend(Gnut_List *list,void *data); Gnut_List * gnut_list_append(Gnut_List *list,void *data, int tracking_number); + Gnut_List * gnut_list_insert_ordered(Gnut_List *list,void *data,int (*cmp)(void *, void *)); Gnut_List * gnut_list_next(Gnut_List *list); Gnut_List * gnut_list_remove(Gnut_List *list, void *data); int gnut_list_foreach(Gnut_List *, int (*a)(void *, void *), void *); diff -Naur gnut-0.4.25/src/share.c gnut-0.4.25-ps0/src/share.c --- gnut-0.4.25/src/share.c Tue Jun 26 23:20:14 2001 +++ gnut-0.4.25-ps0/src/share.c Mon Jul 2 12:06:18 2001 @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef WIN32 #include @@ -402,6 +403,36 @@ return 0; } +/* int share_compare_item(void *si1, void *si2) + * + * Compares two share_items according to alphabetical order. + * We take the lc_path component to determine the ordering, so that + * upper case does not appear before lower case. + */ +int share_compare_item(void *a, void *b) { + share_item *si1=a; + share_item *si2=b; + + return strcmp(si1->lc_path, si2->lc_path); +} + +/* int share_fix_refs(Gnut_List *list) + * + * used to renumber the 'ref' components of the share_items in + * share_root, so that they are in increasing order. This is cosmetic. + */ +int share_fix_refs(Gnut_List *list) { + Gnut_List *item; + int i=1; + share_item *si; + + for (item = list; item != NULL; item = gnut_list_next(item)) { + si = (share_item *)item->data; + si->ref = i++; + } + return 0; +} + #ifdef WIN32 void log_win32_error(char *szFunctionName) { @@ -502,7 +533,7 @@ make_7bit(si->lc_path); pthread_mutex_lock(&share_mutex); - share_root = gnut_list_prepend(share_root, si); + share_root = gnut_list_insert_ordered(share_root,si,share_compare_item); pthread_mutex_unlock(&share_mutex); } } while (FindNextFile(hSearch, &Win32FindData)); @@ -512,144 +543,156 @@ } #endif -/* int scan.dir(char *path) - * - * adds the contents of path to the share_root list */ -int share_scan_dir(char *path, int verbose) -{ -#ifdef WIN32 - share_path_len = strlen(path); - return share_scan_dir_win32(path); -#else - FILE *findfp; - char *leafname; - char *lnend; - char *pathname; +/* ---------------------------------------------------------------------- */ + +#ifndef WIN32 + +/* these functions contributed by Peter Selinger. */ + +int check_for_loops(struct stat *st, Gnut_List **inode_list); +int do_directory(char *path, Gnut_List **inode_list); +int do_path(char *path, Gnut_List **inode_list); +int share_scan_dir_unix(char *path); + +/* structure to hold a pair of an inode and a device: this information + uniquely characterizes a physical file on a given machine, even + across file systems. */ +typedef struct ino_dev_item { + ino_t ino; + dev_t dev; +} ino_dev_item; + +/* check if the file or directory with stat 'st' already exists in the + list '*inode_list'. If yes, return 1. If no, return 0 and update + the list. */ +int check_for_loops(struct stat *st, Gnut_List **inode_list) { + ino_dev_item *id; + Gnut_List *item; + + /* have we seen this inode+device before? */ + for (item = *inode_list; item != NULL; item = gnut_list_next(item)) { + id = (ino_dev_item *)item->data; + if (id->ino == st->st_ino && id->dev == st->st_dev) { + return 1; + } + } + + /* otherwise add it to the list */ + id = (ino_dev_item *)ymaloc(sizeof(ino_dev_item), 10000); + id->ino = st->st_ino; + id->dev = st->st_dev; + *inode_list = gnut_list_prepend(*inode_list, (void *)id); + return 0; +} + +/* add the given file to the share_root list, or traverse it + recursively if it is a directory */ +int do_path(char *path, Gnut_List **inode_list) { struct stat st; int ret; share_item *si; + int i, len; + char *basename; + + ret = stat(path, &st); /* note: stat does the correct thing for symlinks */ + if (ret) /* stat error: gracefully ignore */ + return 0; + + /* if it is a directory, recurse through it, unless we've seen it before */ + if (S_ISDIR(st.st_mode)) { + if (!check_for_loops(&st, inode_list)) + do_directory(path, inode_list); + return 0; + } - gd_s(3, "share_scan_dir entering\n"); + /* if it is an regular file, handle it */ + if (S_ISREG(st.st_mode)) { + si=(share_item *) ymaloc(sizeof(share_item), 10001); + + si->size=st.st_size; + si->mtime=st.st_mtime; + share_size += (double) st.st_size; + si->ref=++share_num; + + /* strip the directory part */ + basename = strrchr(path, '/'); + if (basename == NULL) + basename = path; /* if no '/' found, use entire path */ + else + basename++; /* else strip the '/' */ + + si->path=strdup(basename); /* returned in query reply */ + si->lc_path=strdup(basename); /* used in query match */ + si->fpath=strdup(path); /* real fullpath */ + + len=strlen(si->lc_path); + for (i=0;ilc_path[i]=tolower(si->lc_path[i]); + } + + share_root=gnut_list_insert_ordered(share_root,si,share_compare_item); + return 0; + } - pthread_mutex_lock(&share_mutex); + /* if not a directory or regular file, ignore. */ + return 0; +} - leafname = (char *) ymaloc(OUR_MAX_PATH, 293); - pathname = (char *) ymaloc(OUR_MAX_PATH, 294); - if (have_find) { - if (verbose) { - printf("Using 'find' to index shared files...\n"); - } - sprintf(leafname, "find %s -follow \\( -type f " - "! -name \"*.gnut\" -o -type l \\) " - "-printf %s", path, "\\%P\\\\n\\%p\\\\n"); - } else if (have_perl) { - if (verbose) { - printf("Using 'perl' to index shared files...\n"); - } - sprintf(leafname, - "perl -we '" - - "$r = \"'%s'\"; " /* $r is root */ - "%%visited = (); " - - "sub visit ($) " - "{ " - " local ($p, $f, $d, $i); " /* path file device inode */ - " local *DIR; " - - " $p = shift; " - " opendir DIR, \"$r/$p\"; " - " while ($f = readdir DIR) " - " { " - " next if $f eq \"..\"; " - " ($d, $i) = stat \"$r/$p$f\"; " - " next if $visited{\"$d, $i\"}; " - " $visited{\"$d, $i\"} = 1; " - " next if $f eq \".\"; " - - " if (-f _) " - " { " - " print \"$p$f\\n$r/$p$f\\n\" " - " unless $f =~ /\\.gnut$/; " - " } " - " elsif (-d _) " - " { " - " visit(\"$p$f/\"); " - " } " - " } " - "} " - - "visit(\"\");'", - path); - } else { - printf("NOTE: You cannot 'scan' shared files because you do not have\neither GNU 'find' or 'perl' on your system.\n"); - sprintf(leafname, "echo -n ''"); - } - - gd_s(1, "share_scan_dir about to run: \""); - gd_s(1, leafname); - gd_s(1, "\" \n"); - - /* Open pipe from command */ - findfp = popen(leafname, "r"); - if (findfp == 0) { - gd_s(1, "share_scan_dir pipe to find returned error: "); - gd_i(1, errno); - gd_s(1, "\n"); - pthread_mutex_unlock(&share_mutex); - return -1; - } - gd_s(1, "share_scan_dir retrieving results from find...\n"); - while (fgets(leafname, OUR_MAX_PATH, findfp)) { - if (fgets(pathname, OUR_MAX_PATH, findfp)) { - /* remove trailing eol */ - lnend = leafname + strlen(leafname); lnend--; *lnend = 0; - pathname[strlen(pathname)-1] = 0; - - lnend -= 5; /* for checking for '.gnut' */ - - if (leafname[0] == '.') { - /* ignore dot-files */ - } else if ((strlen(leafname) > 5) - && (lnend[0] == '.') - && (lnend[1] == 'g') - && (lnend[2] == 'n') - && (lnend[3] == 'u') - && (lnend[4] == 't')) { - /* .gnut-files (actually already filtered out by the find command) */ - } else { - ret = stat(pathname, &st); - - si = (share_item *) ymaloc(sizeof(share_item), 295); - - si->size = st.st_size; - si->mtime = st.st_mtime; - share_size += (double) st.st_size; - share_num++; - si->ref = share_num; - - si->path = ystdup(leafname, 433); /* returned in query reply */ - si->lc_path = ystdup(leafname, 434); /* used in query match */ - si->fpath = ystdup(pathname, 435); /* real fullpath */ - - /* lowercase the lc_path */ - make_lc(si->lc_path); - make_7bit(si->lc_path); +/* traverse the directory whose path is given, calling do_path on each + entry */ +int do_directory(char *path, Gnut_List **inode_list) { + DIR *dir; + struct dirent *dirent; - share_root = gnut_list_prepend(share_root, si); - } + dir = opendir(path); /* open directory */ + if (dir==NULL) /* if open fails, ignore gracefully */ + return 0; + while ((dirent = readdir(dir)) != NULL) { /* go through each entry */ + /* make sure to ignore ".." and "." */ + if (strcmp(dirent->d_name, "..")!=0 && strcmp(dirent->d_name, ".")!=0) { + int len = strlen(path)+strlen(dirent->d_name)+2; + char filename[len]; /* Note: don't need alloc. This goes on the stack */ + strcpy(filename, path); + strcat(filename, "/"); + strcat(filename, dirent->d_name); + do_path(filename, inode_list); } } - - pclose(findfp); - fre_str(&leafname, 166); - fre_str(&pathname, 167); - - pthread_mutex_unlock(&share_mutex); - + + closedir(dir); return 0; +} + +/* this is the unix version of share_scan_dir */ +int share_scan_dir_unix(char *path) +{ + Gnut_List *inode_list = NULL; + do_path(path, &inode_list); + gnut_list_fre(inode_list); + share_fix_refs(share_root); + return 0; +} + +#endif /* !WIN32 */ + + +/* int scan_dir(char *path, int verbose) + * + * adds the contents of path to the share_root list */ +int share_scan_dir(char *path, int verbose) +{ +#ifdef WIN32 + int res; + share_path_len=strlen(path); + res = share_scan_dir_win32(path); + share_fix_refs(share_root); + return res; +#else + return share_scan_dir_unix(path); #endif } + +/* ---------------------------------------------------------------------- */ /* my test implementation of search result caching, what I've got is a * hash based on the query token, and a queue based on the time of diff -Naur gnut-0.4.25/src/threads.c gnut-0.4.25-ps0/src/threads.c --- gnut-0.4.25/src/threads.c Tue Jun 12 17:37:14 2001 +++ gnut-0.4.25-ps0/src/threads.c Mon Jul 2 11:37:41 2001 @@ -1718,10 +1718,15 @@ } } if (gc_transferlog) { - fprintf(gc_transferlog, "%d\tr\t%i.%i.%i.%i:%i\t%d\t%d\t%d\t%s\n", - (int) time(0), gt->ip[0], gt->ip[1], gt->ip[2], gt->ip[3], - gt->port, gt->bytes, gt->total, gt->rate_bytes >> 4L, - gt->fname); + time_t t = time(0); + char *timestr = ctime(&t); + char *nl = strchr(timestr, '\n'); + + if (nl) *nl = 0; + fprintf(gc_transferlog, "R %s %i.%i.%i.%i:%i \"%s\" %d/%d @ %sbps\n", + timestr, gt->ip[0], gt->ip[1], gt->ip[2], gt->ip[3], + gt->port, gt->fname, gt->bytes, gt->total, + munge_bytes(gt->rate_bytes >> 4L)); } gd_s(4, "gnut_thr_dl_handle decreasing downloads\n"); } else if (gt->fsock > 0) { diff -Naur gnut-0.4.25/src/transfer.c gnut-0.4.25-ps0/src/transfer.c --- gnut-0.4.25/src/transfer.c Thu Jun 7 15:48:28 2001 +++ gnut-0.4.25-ps0/src/transfer.c Mon Jul 2 11:37:49 2001 @@ -62,8 +62,8 @@ } /* this is called after the file has been opened and the socket - * set up, it either sends or receives the entire content of the - * file, updating the gnut_transfer struc along the way... + * set up, it either sends or receives the entire (or partial) content + * of the file, updating the gnut_transfer struc along the way... * It leaves the structure afterwards though, so that the user * can see downloads that occurred while he/she was away. */ int gnut_transfer_loop(gnut_transfer *gt, int overlap, char *overlap_buf,