diff -urN pacman-2.9.8.orig/libftp/ftplib.c pacman-2.9.8/libftp/ftplib.c --- pacman-2.9.8.orig/libftp/ftplib.c 2004-07-03 06:25:47.000000000 +0200 +++ pacman-2.9.8/libftp/ftplib.c 2006-09-06 19:23:11.000000000 +0200 @@ -1556,6 +1556,103 @@ } /* + * Convert the textual specification of time in TIME_STRING to the + * number of seconds since the Epoch. + * + * TIME_STRING can be in any of the three formats RFC2616 allows the + * HTTP servers to emit -- RFC1123-date, RFC850-date or asctime-date, + * as well as the time format used in the Set-Cookie header. + * Timezones are ignored, and should be GMT. + * + * Taken from http.c of wget-1.10.2 / Tino Reichardt 2006-09-03 + * - changed a bit + * + * return 1 if successful, 0 otherwise + */ +#include +extern char *strptime(const char *s, const char *format, struct tm *tm); +int http_atotm(const char *time_string, struct tm *t) +{ + int i; + + static const char *time_formats[] = { + "%a, %d %b %Y %T", /* rfc1123: Thu, 29 Jan 1998 22:12:57 */ + "%A, %d-%b-%y %T", /* rfc850: Thursday, 29-Jan-98 22:12:57 */ + "%a %b %d %T %Y", /* asctime: Thu Jan 29 22:12:57 1998 */ + "%a, %d-%b-%Y %T" /* cookies: Thu, 29-Jan-1998 22:12:57 (used + in Set-Cookie, defined in the Netscape + cookie specification.) */ + }; + + for (i = 0; i < 5; i++) + { + memset(t, 0, sizeof(struct tm)); + if (strptime(time_string, time_formats[i], t)) + return 1; + } + + /* All formats have failed. */ + return 0; +} + +/* + * HttpModDate - determine the modification date of a remote file + * + * return 1 if successful, 0 otherwise + */ +GLOBALDEF int HttpModDate(const char *host, const char *path, char *dt, int max, + netbuf *nControl) +{ + char buf[256]; + struct tm t; + int rv = 0; + + if ((strlen(path) + 7) > sizeof(buf)) + return 0; + + sprintf(buf, "HEAD %s HTTP/1.1\r\nHost: %s\r\n\r\n", path, host); + + if(!HttpSendCmd(buf,'2',nControl)) + { + if (nControl->response[9] == '3') + printf("redirection not supported\n"); + return 0; + } + + while (1) + { + int ret = 0; + char *buf = nControl->response; + while (ret < 256) { + if (socket_wait(nControl) != 1) + return 0; + if (net_read(nControl->handle,buf,1) != 1) + break; + ret++; + if (*buf == '\r') continue; + if (*buf == '\n') break; + buf++; + } + *buf = 0; + if (strstr(nControl->response,"Last-Modified:")) + { + if (http_atotm(nControl->response+15, &t)) + { + /* 20060830124450 */ + snprintf(dt, max, "%04d%02d%02d%02d%02d%02d", + t.tm_year+1900, t.tm_mon+1, t.tm_mday, + t.tm_hour, t.tm_min, t.tm_sec); + rv = 1; + } + } + if (strlen(nControl->response) == 0) + break; + } + + return rv; +} + +/* * HttpQuit - disconnect from remote * * return 1 if successful, 0 otherwise diff -urN pacman-2.9.8.orig/libftp/ftplib.h pacman-2.9.8/libftp/ftplib.h --- pacman-2.9.8.orig/libftp/ftplib.h 2004-04-19 09:17:56.000000000 +0200 +++ pacman-2.9.8/libftp/ftplib.h 2006-09-03 17:06:21.000000000 +0200 @@ -120,6 +120,7 @@ GLOBALREF void FtpQuit(netbuf *nControl); GLOBALREF int HttpConnect(const char *host, unsigned short port, netbuf **nControl); +GLOBALDEF int HttpModDate(const char *host, const char *path, char *dt, int max, netbuf *nControl); GLOBALREF int HttpGet(const char *host, const char *output, const char *path, int *size, netbuf *nControl, unsigned int offset); GLOBALREF void HttpQuit(netbuf *nControl); diff -urN pacman-2.9.8.orig/src/pacsync.c pacman-2.9.8/src/pacsync.c --- pacman-2.9.8.orig/src/pacsync.c 2006-01-31 01:27:43.000000000 +0100 +++ pacman-2.9.8/src/pacsync.c 2006-09-06 19:11:27.000000000 +0200 @@ -1,8 +1,8 @@ /* * pacsync.c - * + * * Copyright (c) 2002-2006 by Judd Vinet - * + * * This program 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 @@ -143,18 +143,17 @@ return(!!downloadfiles_forreal(servers, localpath, files, NULL, NULL)); } - /* * This is the real downloadfiles, used directly by sync_synctree() to check - * modtimes on remote (ftp only) files. + * modtimes on remote (direct ftp/http only) files. * - if *mtime1 is non-NULL, then only download files * if they are different than *mtime1. String should be in the form * "YYYYMMDDHHMMSS" to match the form of ftplib's FtpModDate() function. * - if *mtime2 is non-NULL, then it will be filled with the mtime - * of the remote FTP file (from MDTM). + * of the remote FTP(MDTM) / HTTP(HEAD Last-Modified) file. * - * NOTE: the *mtime option only works for FTP repositories, and won't work - * if XferCommand is used. We only use it to check mtimes on the + * NOTE: the *mtime option only works for FTP/HTTP repositories, and won't + * work if XferCommand is used. We only use it to check mtimes on the * repo db files. * * RETURN: 0 for successful download @@ -344,7 +343,7 @@ filedone = -1; complete = list_add(complete, fn); } - if(mtime2) { + if(mtime2) { strncpy(mtime2, fmtime, 15); /* YYYYMMDDHHMMSS (=14b) */ mtime2[14] = '\0'; } @@ -372,6 +371,7 @@ char src[PATH_MAX]; char *host; unsigned port; + if(!strcmp(server->protocol, "http") && !pmo_proxyhost) { /* HTTP servers hang up after each request (but not proxies), so * we have to re-connect for each file. @@ -404,13 +404,56 @@ } else { snprintf(src, PATH_MAX, "%s://%s%s%s", server->protocol, server->server, server->path, fn); } - if(!HttpGet(server->server, output, src, &fsz, control, offset)) { - fprintf(stderr, "\nfailed downloading %s from %s: %s\n", - src, server->server, FtpLastResponse(control)); - /* we leave the partially downloaded file in place so it can be resumed later */ - } else { - filedone = 1; + + /* look up Last-Modified Date */ + if(mtime1 || mtime2) { + char fmtime[64]; + if(!HttpModDate(server->server, src, fmtime, sizeof(fmtime)-1, control)) { + fprintf(stderr, "warning: failed to get mtime for %s\n", fn); + } else { + trim(fmtime); + if(mtime1 && !strcmp(mtime1, fmtime)) { + /* mtimes are identical, skip this file */ + vprint("mtimes are identical, skipping %s\n", fn); + filedone = -1; + complete = list_add(complete, fn); + } + if(mtime2) { + strncpy(mtime2, fmtime, 15); /* YYYYMMDDHHMMSS (=14b) */ + mtime2[14] = '\0'; + } + } + } + + if (!filedone) { + host = (pmo_proxyhost) ? pmo_proxyhost : server->server; + port = (pmo_proxyhost) ? pmo_proxyport : 80; + if(strchr(host, ':')) { + vprint("connecting to %s\n", host); + } else { + vprint("connecting to %s:%u\n", host, port); + } + /* we have to re-connect */ + if(!HttpConnect(host, port, &control)) { + fprintf(stderr, "error: cannot connect to %s\n", host); + continue; + } + /* set up our progress bar's callback (and idle timeout) */ + if(strcmp(server->protocol, "file") && control) { + FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control); + FtpOptions(FTPLIB_IDLETIME, (long)1000, control); + FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control); + FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control); + } + if(!HttpGet(server->server, output, src, &fsz, control, offset)) { + fprintf(stderr, "\nfailed downloading %s from %s: %s\n", + src, server->server, FtpLastResponse(control)); + /* we leave the partially downloaded file in place so it can be resumed later */ + } else { + filedone = 1; + } } + /* eof http */ } else if(!strcmp(server->protocol, "file")) { char src[PATH_MAX]; snprintf(src, PATH_MAX, "%s%s", server->path, fn);