--------------------- PatchSet 3729 Date: 2002/03/14 20:23:41 Author: serassio Branch: nt-2_5 Tag: (none) Log: Imported Windows patches from NT-2_3 and Cygwin-svc Members: include/config.h:1.5->1.5.18.1 include/radix.h:1.7->1.7.14.1 include/util.h:1.10->1.10.14.1 lib/ntlmauth.c:1.6->1.6.14.1 lib/util.c:1.12->1.12.14.1 snmplib/parse.c:1.2->1.2.14.1 src/cachemgr.c:1.6->1.6.14.1 src/comm.c:1.18.6.1->1.18.6.1.2.1 src/disk.c:1.8->1.8.22.1 src/fd.c:1.7->1.7.16.1 src/globals.h:1.14->1.14.14.1 src/helper.c:1.16->1.16.10.1 src/ipc.c:1.7->1.7.10.1 src/main.c:1.28.6.1->1.28.6.1.4.1 src/protos.h:1.41.6.3->1.41.6.3.4.1 src/squid.h:1.13.6.2->1.13.6.2.4.1 src/stat.c:1.13->1.13.10.1 src/store_dir.c:1.19->1.19.14.1 src/store_io.c:1.3->1.3.14.1 src/structs.h:1.48->1.48.6.1 src/tools.c:1.19->1.19.14.1 src/win32.c:1.5->1.5.14.1 src/fs/awin32/Makefile:1.1->1.1.2.1 src/fs/awin32/Makefile.am:1.1->1.1.18.1 src/fs/awin32/Makefile.in:1.1->1.1.62.1 src/fs/awin32/aiops.c:1.1->1.1.62.1 src/fs/awin32/async_io.c:1.1->1.1.62.1 src/fs/awin32/store_asyncufs.h:1.1->1.1.62.1 src/fs/awin32/store_dir_aufs.c:1.1->1.1.62.1 src/fs/awin32/store_io_aufs.c:1.1->1.1.62.1 src/fs/ufs/store_dir_ufs.c:1.21.6.1->1.21.6.1.4.1 Index: squid/include/config.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/config.h,v retrieving revision 1.5 retrieving revision 1.5.18.1 diff -u -r1.5 -r1.5.18.1 --- squid/include/config.h 13 Nov 2001 22:19:32 -0000 1.5 +++ squid/include/config.h 14 Mar 2002 20:23:41 -0000 1.5.18.1 @@ -105,7 +105,8 @@ #define _SQUID_CYGWIN_ #elif defined(WIN32) || defined(WINNT) || defined(__WIN32__) || defined(__WIN32) -#define _SQUID_MSWIN_ +#define _SQUID_MSWIN_ /* MS Compilers */ +#include "squid-mswin.h" #elif defined(__APPLE__) #define _SQUID_APPLE_ Index: squid/include/radix.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/radix.h,v retrieving revision 1.7 retrieving revision 1.7.14.1 diff -u -r1.7 -r1.7.14.1 --- squid/include/radix.h 13 Nov 2001 22:19:33 -0000 1.7 +++ squid/include/radix.h 14 Mar 2002 20:23:41 -0000 1.7.14.1 @@ -1,5 +1,5 @@ /* - * $Id: radix.h,v 1.7 2001/11/13 22:19:33 squidadm Exp $ + * $Id: radix.h,v 1.7.14.1 2002/03/14 20:23:41 serassio Exp $ */ #ifndef SQUID_RADIX_H @@ -153,6 +153,8 @@ extern struct squid_radix_node *squid_rn_search(void *, struct squid_radix_node *); extern struct squid_radix_node *squid_rn_search_m(void *, struct squid_radix_node *, void *); extern struct squid_radix_node *squid_rn_lookup(void *, void *, struct squid_radix_node_head *); +#ifndef min #define min(x,y) ((x)<(y)? (x) : (y)) +#endif #endif /* SQUID_RADIX_H */ Index: squid/include/util.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/util.h,v retrieving revision 1.10 retrieving revision 1.10.14.1 diff -u -r1.10 -r1.10.14.1 --- squid/include/util.h 17 Oct 2001 12:30:51 -0000 1.10 +++ squid/include/util.h 14 Mar 2002 20:23:41 -0000 1.10.14.1 @@ -1,5 +1,5 @@ /* - * $Id: util.h,v 1.10 2001/10/17 12:30:51 squidadm Exp $ + * $Id: util.h,v 1.10.14.1 2002/03/14 20:23:41 serassio Exp $ * * AUTHOR: Harvest Derived * @@ -44,11 +44,13 @@ #include #endif -#if !defined(SQUIDHOSTNAMELEN) +#if !defined(SQUIDHOSTNAMELEN) +#ifndef _SQUID_MSWIN_ #include #ifndef _SQUID_NETDB_H_ /* need protection on NEXTSTEP */ #define _SQUID_NETDB_H_ #include +#endif #endif #if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 128) #define SQUIDHOSTNAMELEN 128 @@ -131,5 +133,19 @@ * Returns the amount of known allocated memory */ int statMemoryAccounted(void); + +/* CygWin & Windows NT Port */ +/* win32lib.c */ +#ifdef _SQUID_MSWIN_ +extern int chroot (const char *); +extern int ftruncate(int, off_t); +extern int gettimeofday(struct timeval * ,void *); +extern int kill(pid_t, int); +extern int statfs(const char *, struct statfs *); +extern int truncate(const char *, off_t); +extern const char * wsastrerror(int); +extern struct passwd *getpwnam(char *); +extern struct group *getgrnam(char *); +#endif #endif /* SQUID_UTIL_H */ Index: squid/lib/ntlmauth.c =================================================================== RCS file: /cvsroot/squid-sf//squid/lib/ntlmauth.c,v retrieving revision 1.6 retrieving revision 1.6.14.1 diff -u -r1.6 -r1.6.14.1 --- squid/lib/ntlmauth.c 17 Oct 2001 12:42:58 -0000 1.6 +++ squid/lib/ntlmauth.c 14 Mar 2002 20:23:42 -0000 1.6.14.1 @@ -21,8 +21,8 @@ * */ -#include "ntlmauth.h" #include "util.h" /* for base64-related stuff */ +#include "ntlmauth.h" #ifdef HAVE_STRING_H #include Index: squid/lib/util.c =================================================================== RCS file: /cvsroot/squid-sf//squid/lib/util.c,v retrieving revision 1.12 retrieving revision 1.12.14.1 diff -u -r1.12 -r1.12.14.1 --- squid/lib/util.c 18 Oct 2001 20:52:10 -0000 1.12 +++ squid/lib/util.c 14 Mar 2002 20:23:42 -0000 1.12.14.1 @@ -1,6 +1,6 @@ /* - * $Id: util.c,v 1.12 2001/10/18 20:52:10 squidadm Exp $ + * $Id: util.c,v 1.12.14.1 2002/03/14 20:23:42 serassio Exp $ * * DEBUG: * AUTHOR: Harvest Derived @@ -32,6 +32,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ +#define UTIL_C #define _etext etext Index: squid/snmplib/parse.c =================================================================== RCS file: /cvsroot/squid-sf//squid/snmplib/parse.c,v retrieving revision 1.2 retrieving revision 1.2.14.1 diff -u -r1.2 -r1.2.14.1 --- squid/snmplib/parse.c 18 Oct 2001 20:52:10 -0000 1.2 +++ squid/snmplib/parse.c 14 Mar 2002 20:23:42 -0000 1.2.14.1 @@ -107,6 +107,11 @@ }; int Line = 1; + +#ifdef _SQUID_MSWIN_ +#undef OPAQUE +#undef OPTIONAL +#endif /* types of tokens */ #define CONTINUE -1 Index: squid/src/cachemgr.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/cachemgr.c,v retrieving revision 1.6 retrieving revision 1.6.14.1 diff -u -r1.6 -r1.6.14.1 --- squid/src/cachemgr.c 18 Oct 2001 20:52:11 -0000 1.6 +++ squid/src/cachemgr.c 14 Mar 2002 20:23:43 -0000 1.6.14.1 @@ -1,6 +1,6 @@ /* - * $Id: cachemgr.c,v 1.6 2001/10/18 20:52:11 squidadm Exp $ + * $Id: cachemgr.c,v 1.6.14.1 2002/03/14 20:23:43 serassio Exp $ * * DEBUG: section 0 CGI Cache Manager * AUTHOR: Duane Wessels @@ -169,7 +169,11 @@ static void error_html(const char *msg); static char *menu_url(cachemgr_request * req, const char *action); static int parse_status_line(const char *sline, const char **statusStr); +#ifdef _SQUID_MSWIN_ +static cachemgr_request *read_request(char *); +#else static cachemgr_request *read_request(void); +#endif static char *read_get_request(void); static char *read_post_request(void); @@ -178,6 +182,45 @@ static void reset_auth(cachemgr_request * req); static const char *make_auth_header(const cachemgr_request * req); +#ifdef _SQUID_MSWIN_ +static int s_iInitCount = 0; +int Win32SockInit(void) +{ + int iVersionRequested; + WSADATA wsaData; + int err; + + if (s_iInitCount > 0) { + s_iInitCount++; + return (0); + } + else if (s_iInitCount < 0) + return (s_iInitCount); + + /* s_iInitCount == 0. Do the initailization */ + iVersionRequested = MAKEWORD(2, 0); + err = WSAStartup((WORD) iVersionRequested, &wsaData); + if (err) { + s_iInitCount = -1; + return (s_iInitCount); + } + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 0) { + s_iInitCount = -2; + WSACleanup(); + return (s_iInitCount); + } + s_iInitCount++; + return (s_iInitCount); +} + +void Win32SockCleanup(void) +{ + if (--s_iInitCount == 0) + WSACleanup(); + return; +} +#endif /* ifdef _SQUID_MSWIN_ */ static const char * safe_str(const char *str) @@ -398,7 +441,12 @@ read_reply(int s, cachemgr_request * req) { char buf[4 * 1024]; +#ifdef _SQUID_MSWIN_ + int reply; + FILE *fp = tmpfile(); +#else FILE *fp = fdopen(s, "r"); +#endif /* interpretation states */ enum { isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError @@ -415,6 +463,11 @@ perror("fdopen"); return 1; } +#ifdef _SQUID_MSWIN_ + while ((reply=recv(s,buf,sizeof(buf),0))>0) + fwrite(buf,1,reply,fp); + rewind(fp); +#endif if (parse_menu) action = "menu"; /* read reply interpreting one line at a time depending on state */ @@ -507,6 +560,9 @@ static struct sockaddr_in S; int s; int l; +#ifdef _SQUID_MSWIN_ + int answer; +#endif static char buf[2 * 1024]; if (req == NULL) { auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, ""); @@ -555,9 +611,19 @@ req->hostname, req->action, make_auth_header(req)); +#ifdef _SQUID_MSWIN_ + send(s, buf, l,0); +#else write(s, buf, l); +#endif debug(1) fprintf(stderr, "wrote request: '%s'\n", buf); +#ifdef _SQUID_MSWIN_ + answer=read_reply(s, req); + close(s); + return answer; +#else return read_reply(s, req); +#endif } int @@ -565,16 +631,31 @@ { char *s; cachemgr_request *req; +#ifdef _SQUID_MSWIN_ + int answer; +#endif safe_inet_addr("255.255.255.255", &no_addr); now = time(NULL); +#ifdef _SQUID_MSWIN_ + Win32SockInit(); + if ((s = strrchr(argv[0], '\\'))) +#else if ((s = strrchr(argv[0], '/'))) +#endif progname = xstrdup(s + 1); else progname = xstrdup(argv[0]); if ((s = getenv("SCRIPT_NAME")) != NULL) script_name = xstrdup(s); +#ifdef _SQUID_MSWIN_ + req = read_request(NULL); + answer=process_request(req); + Win32SockCleanup(); + return answer; +#else req = read_request(); return process_request(req); +#endif } static char * @@ -606,10 +687,16 @@ return xstrdup(s); } +#ifdef _SQUID_MSWIN_ +static cachemgr_request * +read_request(char* buf) +{ +#else static cachemgr_request * read_request(void) { char *buf; +#endif cachemgr_request *req; char *s; char *t; @@ -620,7 +707,11 @@ (void) 0; else return NULL; +#ifdef _SQUID_MSWIN_ + if (strlen(buf) == 0 || strlen(buf) == 4000) +#else if (strlen(buf) == 0) +#endif return NULL; req = xcalloc(1, sizeof(cachemgr_request)); for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) { Index: squid/src/comm.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/comm.c,v retrieving revision 1.18.6.1 retrieving revision 1.18.6.1.2.1 diff -u -r1.18.6.1 -r1.18.6.1.2.1 --- squid/src/comm.c 27 Feb 2002 09:18:08 -0000 1.18.6.1 +++ squid/src/comm.c 14 Mar 2002 20:23:43 -0000 1.18.6.1.2.1 @@ -1,6 +1,6 @@ /* - * $Id: comm.c,v 1.18.6.1 2002/02/27 09:18:08 squidadm Exp $ + * $Id: comm.c,v 1.18.6.1.2.1 2002/03/14 20:23:43 serassio Exp $ * * DEBUG: section 5 Socket Functions * AUTHOR: Harvest Derived @@ -32,7 +32,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ - +#ifndef COMM_C +#define COMM_C #include "squid.h" #if defined(_SQUID_CYGWIN_) @@ -173,7 +174,7 @@ const char *note) { int new_socket; - int tos = 0; + int tos; fde *F = NULL; /* Create socket for accepting new connections. */ @@ -774,15 +775,20 @@ { int flags; int dummy = 0; -#ifdef _SQUID_CYGWIN_ +#if defined (_SQUID_CYGWIN_) || defined (_SQUID_MSWIN_) int nonblocking = TRUE; +#ifdef _SQUID_CYGWIN_ if (fd_table[fd].type != FD_PIPE) { +#endif if (ioctl(fd, FIONBIO, &nonblocking) < 0) { debug(50, 0) ("commSetNonBlocking: FD %d: %s %D\n", fd, xstrerror(), fd_table[fd].type); return COMM_ERROR; } +#ifdef _SQUID_CYGWIN_ } else { #endif +#endif +#ifndef _SQUID_MSWIN_ if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) { debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror()); return COMM_ERROR; @@ -791,6 +797,7 @@ debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } +#endif #ifdef _SQUID_CYGWIN_ } #endif @@ -801,13 +808,18 @@ int commUnsetNonBlocking(int fd) { - int flags; int dummy = 0; +#ifdef _SQUID_MSWIN_ + int nonblocking = FALSE; + if (ioctlsocket(fd, FIONBIO, (unsigned long *) &nonblocking) < 0) { +#else + int flags; if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) { debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror()); return COMM_ERROR; } if (fcntl(fd, F_SETFL, flags & (~SQUID_NONBLOCK)) < 0) { +#endif debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } @@ -999,3 +1011,4 @@ } } } +#endif /* COMM_C */ Index: squid/src/disk.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/disk.c,v retrieving revision 1.8 retrieving revision 1.8.22.1 diff -u -r1.8 -r1.8.22.1 --- squid/src/disk.c 16 Aug 2001 07:39:03 -0000 1.8 +++ squid/src/disk.c 14 Mar 2002 20:23:43 -0000 1.8.22.1 @@ -1,6 +1,6 @@ /* - * $Id: disk.c,v 1.8 2001/08/16 07:39:03 squidadm Exp $ + * $Id: disk.c,v 1.8.22.1 2002/03/14 20:23:43 serassio Exp $ * * DEBUG: section 6 Disk I/O Routines * AUTHOR: Harvest Derived @@ -60,17 +60,39 @@ file_open(const char *path, int mode) { int fd; +#ifdef _SQUID_MSWIN_ + char fmode[4]=""; + FILE * fbuf; +#endif if (mode & O_WRONLY) mode |= O_APPEND; +#ifdef _SQUID_MSWIN_ + mode |= _O_BINARY; + errno = 0; + if (mode & O_WRONLY) { + if (mode & O_TRUNC) + strcpy(fmode,"wb"); + else + strcpy(fmode,"a+b"); + } + else + strcpy(fmode,"rb"); + fbuf=fopen(path,fmode); + fd = (fbuf != NULL) ? fileno(fbuf) : -1; +#else mode |= SQUID_NONBLOCK; errno = 0; fd = open(path, mode, 0644); +#endif statCounter.syscalls.disk.opens++; if (fd < 0) { debug(50, 3) ("file_open: error opening file %s: %s\n", path, xstrerror()); fd = DISK_ERROR; } else { +#ifdef _SQUID_MSWIN_ + fd_table[fd].fbuf=fbuf; +#endif debug(6, 5) ("file_open: FD %d\n", fd); commSetCloseOnExec(fd); fd_open(fd, FD_FILE, path); @@ -83,6 +105,9 @@ void file_close(int fd) { +#ifdef _SQUID_MSWIN_ + FILE *fbuf; +#endif fde *F = &fd_table[fd]; PF *read_callback; assert(fd >= 0); @@ -114,7 +139,15 @@ #if CALL_FSYNC_BEFORE_CLOSE fsync(fd); #endif +#ifdef _SQUID_MSWIN_ + fbuf = fd_table[fd].fbuf; + if (fbuf == NULL) + close(fd); + else + fclose(fbuf); +#else close(fd); +#endif debug(6, F->flags.close_request ? 2 : 5) ("file_close: FD %d, really closing\n", fd); fd_close(fd); Index: squid/src/fd.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/fd.c,v retrieving revision 1.7 retrieving revision 1.7.16.1 diff -u -r1.7 -r1.7.16.1 --- squid/src/fd.c 26 Aug 2001 22:26:29 -0000 1.7 +++ squid/src/fd.c 14 Mar 2002 20:23:43 -0000 1.7.16.1 @@ -1,6 +1,6 @@ /* - * $Id: fd.c,v 1.7 2001/08/26 22:26:29 squidadm Exp $ + * $Id: fd.c,v 1.7.16.1 2002/03/14 20:23:43 serassio Exp $ * * DEBUG: section 51 Filedescriptor Functions * AUTHOR: Duane Wessels @@ -96,13 +96,21 @@ int default_read_method(int fd, char *buf, int len) { +#ifdef _SQUID_MSWIN_ + return (fread(buf, 1, len, fd_table[fd].fbuf)); +#else return (read(fd, buf, len)); +#endif } int default_write_method(int fd, const char *buf, int len) { - return (write(fd, buf, len)); +#ifdef _SQUID_MSWIN_ + return (fwrite(buf, 1, len, fd_table[fd].fbuf)); +#else + return (write(fd, buf, len)); +#endif } void Index: squid/src/globals.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/globals.h,v retrieving revision 1.14 retrieving revision 1.14.14.1 diff -u -r1.14 -r1.14.14.1 --- squid/src/globals.h 18 Oct 2001 20:52:11 -0000 1.14 +++ squid/src/globals.h 14 Mar 2002 20:23:44 -0000 1.14.14.1 @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.14 2001/10/18 20:52:11 squidadm Exp $ + * $Id: globals.h,v 1.14.14.1 2002/03/14 20:23:44 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -159,7 +159,14 @@ extern int incoming_sockets_accepted; #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ -extern char *WIN32_OS_string; +extern char *WIN32_OS_string; /* NULL */ +extern char *WIN32_Service_name; /* NULL */ +extern char *WIN32_Command_Line; /* NULL */ +extern char *WIN32_Service_Command_Line; /* NULL */ +extern unsigned int WIN32_run_mode; /* _WIN_SQUID_RUN_MODE_INTERACTIVE */ +#if defined(_SQUID_MSWIN_) && defined(_DEBUG) +extern int do_debug; /* 0 */ +#endif #endif #endif /* SQUID_GLOBALS_H */ Index: squid/src/helper.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/helper.c,v retrieving revision 1.16 retrieving revision 1.16.10.1 diff -u -r1.16 -r1.16.10.1 --- squid/src/helper.c 28 Nov 2001 23:29:52 -0000 1.16 +++ squid/src/helper.c 14 Mar 2002 20:23:44 -0000 1.16.10.1 @@ -1,6 +1,6 @@ /* - * $Id: helper.c,v 1.16 2001/11/28 23:29:52 squidadm Exp $ + * $Id: helper.c,v 1.16.10.1 2002/03/14 20:23:44 serassio Exp $ * * DEBUG: section 29 Helper process maintenance * AUTHOR: Harvest Derived? @@ -32,6 +32,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ +#ifndef HELPER_C +#define HELPER_C #include "squid.h" @@ -73,6 +75,11 @@ int rfd; int wfd; wordlist *w; +#ifdef _SQUID_MSWIN_ + HANDLE hIpc; + pid_t pid; +#endif + if (hlp->cmdline == NULL) return; progname = hlp->cmdline->key; @@ -97,7 +104,11 @@ args, shortname, &rfd, - &wfd); + &wfd +#ifdef _SQUID_MSWIN_ + , &hIpc, &pid +#endif + ); if (x < 0) { debug(29, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; @@ -112,6 +123,10 @@ srv->buf_sz = 8192; srv->offset = 0; srv->parent = hlp; +#ifdef _SQUID_MSWIN_ + srv->hIpc = hIpc; + srv->pid = pid; +#endif cbdataLock(hlp); /* lock because of the parent backlink */ dlinkAddTail(srv, &srv->link, &hlp->servers); if (rfd == wfd) { @@ -149,6 +164,11 @@ int rfd; int wfd; wordlist *w; +#ifdef _SQUID_MSWIN_ + HANDLE hIpc; + pid_t pid; +#endif + if (hlp->cmdline == NULL) return; progname = hlp->cmdline->key; @@ -173,7 +193,11 @@ args, shortname, &rfd, - &wfd); + &wfd +#ifdef _SQUID_MSWIN_ + , &hIpc, &pid +#endif + ); if (x < 0) { debug(29, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; @@ -507,6 +531,11 @@ { dlink_node *link = hlp->servers.head; helper_server *srv; +#ifdef _SQUID_MSWIN_ + HANDLE hIpc; + pid_t pid; + int no; +#endif while (link) { srv = link->data; link = link->next; @@ -527,8 +556,25 @@ continue; } srv->flags.closing = 1; +#ifdef _SQUID_MSWIN_ + hIpc = srv->hIpc; + pid = srv->pid; + no = srv->index + 1; + shutdown(srv->rfd, SD_BOTH); +#endif comm_close(srv->wfd); srv->wfd = -1; +#ifdef _SQUID_MSWIN_ + if (hIpc) { + if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) { + getCurrentTime(); + debug(34, 1) ("helperShutdown: WARNING: %s #%d (%s,%ld) " + "didn't exit in 5 seconds\n", + hlp->id_name, no, hlp->cmdline->key, pid); + } + CloseHandle(hIpc); + } +#endif } } @@ -1115,3 +1161,4 @@ xfree(r->buf); memFree(r, MEM_HELPER_STATEFUL_REQUEST); } +#endif /* HELPER_C */ Index: squid/src/ipc.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ipc.c,v retrieving revision 1.7 retrieving revision 1.7.10.1 diff -u -r1.7 -r1.7.10.1 --- squid/src/ipc.c 18 Oct 2001 20:52:11 -0000 1.7 +++ squid/src/ipc.c 14 Mar 2002 20:23:44 -0000 1.7.10.1 @@ -1,6 +1,6 @@ /* - * $Id: ipc.c,v 1.7 2001/10/18 20:52:11 squidadm Exp $ + * $Id: ipc.c,v 1.7.10.1 2002/03/14 20:23:44 serassio Exp $ * * DEBUG: section 54 Interprocess Communication * AUTHOR: Duane Wessels @@ -35,6 +35,35 @@ #include "squid.h" +#ifdef _SQUID_MSWIN_ +#include + +struct ipc_params +{ + int type; + int crfd; + int cwfd; + struct sockaddr_in PS; + const char *prog; + char **args; +}; + +static struct thread_params +{ + int type; + int rfd; + int send_fd; + const char *prog; + pid_t pid; +}; +static int __stdcall ipc_thread_1(struct ipc_params *params); +static int __stdcall ipc_thread_2(struct thread_params *params); + +static const char *ok_string = "OK\n"; +static const char *err_string = "ERR\n"; +static const char *shutdown_string = "$shutdown\n"; +#endif + static const char *hello_string = "hi there\n"; #define HELLO_BUF_SZ 32 static char hello_buf[HELLO_BUF_SZ]; @@ -56,8 +85,16 @@ } int +#ifdef _SQUID_MSWIN_ +ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, HANDLE * hIpc, pid_t * ppid) +#else ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd) +#endif { +#ifdef _SQUID_MSWIN_ + unsigned long thread; + struct ipc_params params; +#endif pid_t pid; struct sockaddr_in CS; struct sockaddr_in PS; @@ -65,13 +102,15 @@ int prfd = -1; int cwfd = -1; int pwfd = -1; + socklen_t len; +#ifndef _SQUID_MSWIN_ int fd; int t1, t2, t3; - socklen_t len; int tmp_s; #if HAVE_PUTENV char *env_str; #endif +#endif int x; #if HAVE_POLL && defined(_SQUID_OSF_) @@ -82,6 +121,12 @@ *rfd = -1; if (wfd) *wfd = -1; +#ifdef _SQUID_MSWIN_ + if (hIpc) + *hIpc = NULL; + if (ppid) + *ppid = -1; +#endif if (type == IPC_TCP_SOCKET) { crfd = cwfd = comm_open(SOCK_STREAM, 0, @@ -109,6 +154,12 @@ 0, name); } else if (type == IPC_FIFO) { +#ifdef _SQUID_MSWIN_ + debug(54, 0) + ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n", + prog); + assert(0); +#else int p2c[2]; int c2p[2]; if (pipe(p2c) < 0) { @@ -123,6 +174,7 @@ fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write"); fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read"); fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write"); +#endif } else { assert(IPC_NONE); } @@ -139,7 +191,11 @@ debug(54, 0) ("ipcCreate: Failed to create server FD.\n"); return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); } +#ifdef _SQUID_MSWIN_ + { +#else if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { +#endif len = sizeof(PS); memset(&PS, '\0', len); if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) { @@ -166,10 +222,25 @@ } /* flush or else we get dup data if unbuffered_logs is set */ logsFlush(); +#ifdef _SQUID_MSWIN_ + params.type = type; + params.crfd = crfd; + params.cwfd = cwfd; + params.PS = PS; + params.prog = prog; + params.args = (char **) args; + + thread = _beginthreadex(NULL, 0, ipc_thread_1, ¶ms, 0, NULL); + + if (thread == 0) { + debug(50, 1) ("ipcCreate: _beginthread: %s\n", xstrerror()); +#else if ((pid = fork()) < 0) { debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror()); +#endif return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); } +#ifndef _SQUID_MSWIN_ if (pid > 0) { /* parent */ /* close shared socket with child */ comm_close(crfd); @@ -177,14 +248,23 @@ comm_close(cwfd); cwfd = crfd = -1; if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { +#else +#undef ipcCloseAllFD +#define ipcCloseAllFD(w,x,y,z) (CloseHandle((HANDLE)thread), ipcCloseAllFD((w),(x),-1,-1)) + { +#endif if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); } memset(hello_buf, '\0', HELLO_BUF_SZ); - if (type == IPC_UDP_SOCKET) +#ifndef _SQUID_MSWIN_ + if (type == IPC_UDP_SOCKET) +#endif x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0); - else - x = read(prfd, hello_buf, HELLO_BUF_SZ - 1); +#ifndef _SQUID_MSWIN_ + else + x = read(prfd, hello_buf, HELLO_BUF_SZ - 1); +#endif if (x < 0) { debug(50, 0) ("ipcCreate: PARENT: hello read test failed\n"); debug(50, 0) ("--> read: %s\n", xstrerror()); @@ -195,6 +275,28 @@ debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); } +#ifdef _SQUID_MSWIN_ + x = send(pwfd, ok_string, strlen(ok_string), 0); + if (x < 0) { + debug(50, 0) ("ipcCreate: PARENT: OK write test failed\n"); + debug(50, 0) ("--> read: %s\n", xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + memset(hello_buf, '\0', HELLO_BUF_SZ); + x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0); + if (x < 0) { + debug(50, 0) ("ipcCreate: PARENT: OK read test failed\n"); + debug(50, 0) ("--> read: %s\n", xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } else if (!strcmp(hello_buf, err_string)) { + debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + hello_buf[x] = '\0'; + pid = atol(hello_buf); +#endif commSetTimeout(prfd, -1, NULL, NULL); commSetNonBlocking(prfd); commSetNonBlocking(pwfd); @@ -202,6 +304,23 @@ *rfd = prfd; if (wfd) *wfd = pwfd; +#ifdef _SQUID_MSWIN_ + fd_table[prfd].flags.ipc = 1; + fd_table[pwfd].flags.ipc = 1; + fd_table[crfd].flags.ipc = 1; + fd_table[cwfd].flags.ipc = 1; + { + DWORD ecode = 0; + if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) { + if (hIpc) + *hIpc = (HANDLE) thread; + if (ppid) + *ppid = pid; + return pwfd; + } else + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } +#else fd_table[prfd].flags.ipc = 1; fd_table[pwfd].flags.ipc = 1; if (Config.sleep_after_fork) { @@ -212,7 +331,63 @@ select(0, NULL, NULL, NULL, &sl); } return pid; +#endif } + +#ifdef _SQUID_MSWIN_ +#undef ipcCloseAllFD + +static int +ipcSend(int cwfd, const char *buf, int len) +{ + int x; + + x = send(cwfd, buf, len, 0); + if (x < 0) { + debug(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); + debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n"); + } + return x; +} + +static int __stdcall +ipc_thread_1(struct ipc_params *params) +{ + int retval = -1; + int t1, t2, t3; + int p2c[2] = { -1, -1 }; + int c2p[2] = { -1, -1 }; + HANDLE hProcess = NULL; + pid_t pid; + HANDLE thread = NULL; + struct thread_params thread_params; + int fd; + char *str; + int tmp_s; +#if HAVE_PUTENV + char *env_str = NULL; +#endif + int x; + int type = params->type; + int crfd = params->crfd; + int cwfd = params->cwfd; + int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1; + char *prog = NULL; + char **args = params->args; + struct sockaddr_in PS = params->PS; + struct sockaddr_in CS_ipc, PS_ipc; + char *buf1 = NULL; + + buf1 = xcalloc(1, 8192); + strcpy(buf1, params->prog); + prog = strtok(buf1, w_space); + if (str = strrchr(prog, '/')) + prog = ++str; + if (str = strrchr(prog, '\\')) + prog = ++str; + prog = xstrdup(prog); + +#else /* child */ no_suid(); /* give up extra priviliges */ /* close shared socket with parent */ @@ -220,25 +395,47 @@ if (pwfd != prfd) close(pwfd); pwfd = prfd = -1; +#endif if (type == IPC_TCP_SOCKET) { debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd); if ((fd = accept(crfd, NULL, NULL)) < 0) { debug(50, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror()); - _exit(1); +#ifdef _SQUID_MSWIN_ + goto cleanup; +#else + _exit(1); +#endif } debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd); - close(crfd); +#ifdef _SQUID_MSWIN_ + comm_close(crfd); + snprintf(buf1, 8191, "%s CHILD socket", prog); + fd_open(fd, FD_SOCKET, buf1); + fd_table[fd].flags.ipc = 1; +#else + close(crfd); +#endif cwfd = crfd = fd; } else if (type == IPC_UDP_SOCKET) { if (comm_connect_addr(crfd, &PS) == COMM_ERROR) +#ifdef _SQUID_MSWIN_ + goto cleanup; +#else return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); +#endif } +#ifndef _SQUID_MSWIN_ if (type == IPC_UDP_SOCKET) { +#endif x = send(cwfd, hello_string, strlen(hello_string) + 1, 0); if (x < 0) { debug(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n"); +#ifdef _SQUID_MSWIN_ + goto cleanup; + } +#else _exit(1); } } else { @@ -248,11 +445,13 @@ _exit(1); } } +#endif #if HAVE_PUTENV env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1); snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions); putenv(env_str); #endif +#ifndef _SQUID_MSWIN_ /* * This double-dup stuff avoids problems when one of * crfd, cwfd, or debug_log are in the rage 0-2. @@ -286,4 +485,359 @@ debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror()); _exit(1); return 0; +#else + memset(buf1, '\0', sizeof(buf1)); + x = recv(crfd, buf1, 8191, 0); + if (x < 0) { + debug(50, 0) ("ipcCreate: CHILD: OK read test failed\n"); + debug(50, 0) ("--> read: %s\n", xstrerror()); + goto cleanup; + } else if (strcmp(buf1, ok_string)) { + debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); + goto cleanup; + } + /* assign file descriptors to child process */ + if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) { + debug(50, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) { + debug(50, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + if (type == IPC_UDP_SOCKET) { + snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1); + crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, 0, local_addr, 0, 0, buf1); + + if (crfd_ipc < 0) { + debug(54, + 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1); + prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, 0, local_addr, 0, 0, buf1); + if (pwfd_ipc < 0) { + debug(54, + 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + tmp_s = sizeof(PS_ipc); + memset(&PS_ipc, '\0', tmp_s); + if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) { + debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port)); + tmp_s = sizeof(CS_ipc); + memset(&CS_ipc, '\0', tmp_s); + if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) { + debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port)); + + if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) { + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + fd = crfd; + + if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) { + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + } /* IPC_UDP_SOCKET */ + t1 = dup(0); + t2 = dup(1); + t3 = dup(2); + dup2(c2p[0], 0); + dup2(p2c[1], 1); + dup2(fileno(debug_log), 2); + close(c2p[0]); + close(p2c[1]); + + commUnsetNonBlocking(fd); + + { + STARTUPINFO si; + PROCESS_INFORMATION pi; + + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdInput = (HANDLE) _get_osfhandle(0); + si.hStdOutput = (HANDLE) _get_osfhandle(1); + si.hStdError = (HANDLE) _get_osfhandle(2); + si.dwFlags = STARTF_USESTDHANDLES; + + *buf1 = '\0'; + strcpy(buf1 + 4096, params->prog); + str = strtok(buf1 + 4096, w_space); + do { + strcat(buf1, str); + strcat(buf1, " "); + } while ((str = strtok(NULL, w_space))); + x = 1; + while (args[x]) { + strcat(buf1, args[x++]); + strcat(buf1, " "); + } + + if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW, + NULL, NULL, &si, &pi)) { + pid = pi.dwProcessId; + hProcess = pi.hProcess; + } else { + pid = -1; + _dosmaperr(GetLastError()); + x = errno; + } + } + dup2(t1, 0); + dup2(t2, 1); + dup2(t3, 2); + close(t1); + close(t2); + close(t3); + + if (pid == -1) { + errno = x; + debug(50, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + if (type == IPC_UDP_SOCKET) { + WSAPROTOCOL_INFO wpi; + + memset(&wpi, 0, sizeof(wpi)); + if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) { + debug(50, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n", + xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + x = write(c2p[1], &wpi, sizeof(wpi)); + if (x < sizeof(wpi)) { + debug(50, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + x = read(p2c[0], buf1, 8192); + if (x < 0) { + debug(50, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } else if (strncmp(buf1, ok_string, strlen(ok_string))) { + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + debug(54, 0) ("--> read returned %d\n", x); + buf1[x] = '\0'; + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + x = write(c2p[1], &PS_ipc, sizeof(PS_ipc)); + if (x < sizeof(PS_ipc)) { + debug(50, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + x = read(p2c[0], buf1, 8192); + if (x < 0) { + debug(50, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } else if (strncmp(buf1, ok_string, strlen(ok_string))) { + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + buf1[x] = '\0'; + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + x = send(pwfd_ipc, ok_string, strlen(ok_string), 0); + x = recv(prfd_ipc, buf1 + 200, 8191 - 200, 0); + assert((size_t) x == strlen(ok_string) + && !strncmp(ok_string, buf1 + 200, strlen(ok_string))); + } /* IPC_UDP_SOCKET */ + snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, pid); + fd_note(fd, buf1); + if (prfd_ipc != -1) { + snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, pid); + fd_note(crfd_ipc, buf1); + snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, pid); + fd_note(prfd_ipc, buf1); + } /* else { // IPC_TCP_SOCKET + * commSetNoLinger(fd); + * } + */ + thread_params.prog = prog; + thread_params.send_fd = cwfd; + thread_params.pid = pid; + if ((thread_params.type = type) == IPC_TCP_SOCKET) + thread_params.rfd = p2c[0]; + else + thread_params.rfd = prfd_ipc; + + thread = + (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL); + if (!thread) { + debug(50, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + snprintf(buf1, 8191, "%ld\n", pid); + if (-1 == ipcSend(cwfd, buf1, strlen(buf1))) + goto cleanup; + + debug(54, 2) ("ipc(%s,%d): started successfully\n", prog, pid); + /* cycle */ + for (;;) { + x = recv(crfd, buf1, 8192, 0); + if (x <= 0) { + debug(54, + 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n", + prog, pid, x); + break; + } + buf1[x] = '\0'; + if (type == 2 && !strcmp(buf1, shutdown_string)) { + debug(54, 3) + + ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n", + prog, pid); + break; + } + debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid, + rfc1738_escape_unescaped(buf1)); + if (type == IPC_TCP_SOCKET) + x = write(c2p[1], buf1, x); + else + x = send(pwfd_ipc, buf1, x, 0); + if (x <= 0) { + debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n", + prog, pid, x, prog); + break; + } + } + + retval = 0; + + cleanup: + if (c2p[1] != -1) + close(c2p[1]); + if (fd_table[crfd].flags.open) + ipcCloseAllFD(-1, -1, crfd, cwfd); + if (prfd_ipc != -1) { + send(crfd_ipc, shutdown_string, strlen(shutdown_string), 0); + shutdown(crfd_ipc, SD_BOTH); + shutdown(prfd_ipc, SD_BOTH); + } + ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc); + if (hProcess && WAIT_OBJECT_0 != + WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) { + + getCurrentTime(); + debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n", + prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5); + } + if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) { + getCurrentTime(); + debug(54, 0) + ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n", + prog, pid, prog); + } + getCurrentTime(); + if (!retval) + debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid); + + if (buf1) + xfree(buf1); + if (prog) + xfree(prog); + if (env_str) + xfree(env_str); + if (thread) + CloseHandle(thread); + if (hProcess) + CloseHandle(hProcess); + if (p2c[0] != -1) + close(p2c[0]); + return retval; +#endif +} + +#ifdef _SQUID_MSWIN_ +static int __stdcall +ipc_thread_2(struct thread_params *params) +{ + int type = params->type; + int rfd = params->rfd; + int send_fd = params->send_fd; + int x; + char *prog = xstrdup(params->prog); + pid_t pid = params->pid; + char *buf2 = xcalloc(1, 8192); + + for (;;) { + if (type == IPC_TCP_SOCKET) + x = read(rfd, buf2, 8192); + else + x = recv(rfd, buf2, 8192, 0); + if ((x <= 0 && type == IPC_TCP_SOCKET) || (x < 0 + && type == IPC_UDP_SOCKET)) { + debug(54, 3) ("ipc(%s,%d): %d bytes read from %s. Exiting...\n", + prog, pid, x, prog); + break; + } + buf2[x] = '\0'; + if (type == 2 && !strcmp(buf2, shutdown_string)) { + debug(54, + 3) ("ipc(%s,%d): request for shutdown received. Exiting...\n", + prog, pid); + break; + } + debug(54, 5) ("ipc(%s,%d): received from child : %s\n", prog, pid, + rfc1738_escape_unescaped(buf2)); + x = send(send_fd, buf2, x, 0); + if ((x <= 0 && type == IPC_TCP_SOCKET) || (x < 0 + && type == IPC_UDP_SOCKET)) { + debug(54, 3) ("ipc(%s,%d): %d bytes sent to parent. Exiting...\n", + prog, pid, x); + break; + } + } + xfree(prog); + xfree(buf2); + return 0; } +#endif Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.28.6.1 retrieving revision 1.28.6.1.4.1 diff -u -r1.28.6.1 -r1.28.6.1.4.1 --- squid/src/main.c 16 Jan 2002 09:32:28 -0000 1.28.6.1 +++ squid/src/main.c 14 Mar 2002 20:23:44 -0000 1.28.6.1.4.1 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.28.6.1 2002/01/16 09:32:28 squidadm Exp $ + * $Id: main.c,v 1.28.6.1.4.1 2002/03/14 20:23:44 serassio Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -35,11 +35,26 @@ #include "squid.h" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +#include +#include +static int opt_install_service = FALSE; +static int opt_remove_service = FALSE; +static int opt_signal_service = FALSE; +static int opt_command_line = FALSE; +extern void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +#endif + /* for error reporting from xmalloc and friends */ extern void (*failure_notify) (const char *); static int opt_send_signal = -1; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +static int opt_no_daemon = 1; +#else static int opt_no_daemon = 0; +#endif static int opt_parse_cfg_only = 0; static int httpPortNumOverride = 1; static int icpPortNumOverride = 1; /* Want to detect "-u 0" */ @@ -53,8 +68,6 @@ static void mainRotate(void); static void mainReconfigure(void); -static SIGHDLR rotate_logs; -static SIGHDLR reconfigure; #if ALARM_UPDATES_TIME static SIGHDLR time_tick; #endif @@ -83,15 +96,27 @@ usage(void) { fprintf(stderr, +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + "Usage: %s [-dhirsvzCDFRVYX] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n" +#else "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n" +#endif " -a port Specify HTTP port number (default: %d).\n" " -d level Write debugging to stderr also.\n" " -f file Use given config-file instead of\n" " %s\n" " -h Print help message.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -i Installs as a Windows Service (see -n option).\n" +#endif " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n" " Parse configuration file, then send signal to \n" " running copy (except -k parse) and exit.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -n name Specify Windows Service name to use for service operations\n" + " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n" + " -r Removes a Windows Service (see -n option).\n" +#endif " -s Enable logging to syslog.\n" " -u port Specify ICP port number (default: %d), disable with 0.\n" " -v Print version.\n" @@ -99,7 +124,12 @@ " -C Do not catch fatal signals.\n" " -D Disable initial DNS tests.\n" " -F Don't serve any requests until store is rebuilt.\n" +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) " -N No daemon mode.\n" +#else + " -O options\n" + " Set Windows Service Command line options in Registry.\n" +#endif " -R Do not set REUSEADDR on port.\n" " -S Double-check swap during rebuild.\n" " -V Virtual host httpd-accelerator.\n" @@ -115,7 +145,11 @@ extern char *optarg; int c; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + while ((c = getopt(argc, argv, "CDFO:RSVYXa:d:f:hik:m::n:rsu:vz?")) != -1) { +#else while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) { +#endif switch (c) { case 'C': opt_catch_signals = 0; @@ -126,9 +160,16 @@ case 'F': opt_foreground_rebuild = 1; break; +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) case 'N': opt_no_daemon = 1; break; +#else + case 'O': + opt_command_line = 1; + WIN32_Command_Line = xstrdup(optarg); + break; +#endif case 'R': opt_reuseaddr = 0; break; @@ -158,6 +199,11 @@ case 'h': usage(); break; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'i': + opt_install_service = TRUE; + break; +#endif case 'k': if ((int) strlen(optarg) < 1) usage(); @@ -205,6 +251,16 @@ fatal("Need to configure --enable-xmalloc-debug-trace to use -m option"); #endif } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'n': + xfree(WIN32_Service_name); + WIN32_Service_name = xstrdup(optarg); + opt_signal_service = TRUE; + break; + case 'r': + opt_remove_service = TRUE; + break; +#endif case 's': opt_syslog_enable = 1; break; @@ -215,6 +271,9 @@ break; case 'v': printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + printf("Compiled as Windows System Service.\n"); +#endif exit(0); /* NOTREACHED */ case 'z': @@ -229,13 +288,15 @@ } /* ARGSUSED */ -static void +void rotate_logs(int sig) { do_rotate = 1; +#ifndef _SQUID_MSWIN_ #if !HAVE_SIGACTION signal(sig, rotate_logs); #endif +#endif } #if ALARM_UPDATES_TIME @@ -252,19 +313,22 @@ #endif /* ARGSUSED */ -static void +void reconfigure(int sig) { do_reconfigure = 1; +#ifndef _SQUID_MSWIN_ #if !HAVE_SIGACTION signal(sig, reconfigure); #endif +#endif } void shut_down(int sig) { do_shutdown = sig == SIGINT ? -1 : 1; +#ifndef _SQUID_MSWIN_ #ifdef KILL_PARENT_OPT if (getppid() > 1) { debug(1, 1) ("Killing RunCache, pid %d\n", getppid()); @@ -275,6 +339,7 @@ signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); #endif +#endif } static void @@ -292,7 +357,9 @@ wccpConnectionOpen(); #endif clientdbInit(); +#ifndef _SQUID_MSWIN_ icmpOpen(); +#endif netdbInit(); asnInit(); peerSelectInit(); @@ -411,7 +478,7 @@ leave_suid(); /* Run as non privilegied user */ #ifdef _SQUID_OS2_ return; -#endif +#else if (geteuid() == 0) { debug(0, 0) ("Squid is not safe to run as root! If you must\n"); debug(0, 0) ("start Squid as root, then you must configure\n"); @@ -419,6 +486,7 @@ debug(0, 0) ("'cache_effective_user' option in the config file.\n"); fatal("Don't run Squid as root, set 'cache_effective_user'!"); } +#endif } static void @@ -472,6 +540,14 @@ debug(1, 0) ("Starting Squid Cache version %s for %s...\n", version_string, CONFIG_HOST_TYPE); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string); + debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line); + } + else + debug(1, 0) ("Running on %s\n",WIN32_OS_string); +#endif debug(1, 1) ("Process ID %d\n", (int) getpid()); debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD); @@ -563,24 +639,35 @@ configured_once = 1; } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */ +void WINAPI +SquidMain(int argc, char **argv) +#else int main(int argc, char **argv) +#endif { int errcount = 0; int n; /* # of GC'd objects */ time_t loop_delay; mode_t oldmask; -#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - int WIN32_init_err; -#endif debug_log = stderr; if (FD_SETSIZE < Squid_MaxFD) Squid_MaxFD = FD_SETSIZE; #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - if ((WIN32_init_err = WIN32_Subsystem_Init())) - return WIN32_init_err; +#ifdef USE_WIN32_SERVICE + if (WIN32_Subsystem_Init(&argc, &argv)) + return; +#else + { + int WIN32_init_err; + if ((WIN32_init_err = WIN32_Subsystem_Init())) + return WIN32_init_err; + } +#endif #endif /* call mallopt() before anything else */ @@ -621,8 +708,26 @@ squid_start = current_time; failure_notify = fatal_dump; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainParseOptions(argc, argv); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_install_service) { + WIN32_InstallService(); + return; + } + if (opt_remove_service) { + WIN32_RemoveService(); + return; + } + if (opt_command_line) { + WIN32_SetServiceCommandLine(); + return; + } +#endif + /* parse configuration file * note: in "normal" case this used to be called from mainInitialize() */ { @@ -641,7 +746,11 @@ parse_err = parseConfigFile(ConfigFile); if (opt_parse_cfg_only) +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return parse_err; +#endif } if (-1 == opt_send_signal) if (checkRunningPid()) @@ -672,7 +781,11 @@ setEffectiveUser(); debug(0, 0) ("Creating Swap Directories\n"); storeCreateSwapDirectories(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } if (!opt_no_daemon) watch_child(argv); @@ -686,14 +799,25 @@ comm_init(); comm_select_init(); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_INTERACTIVE) && (opt_no_daemon)) { +#else if (opt_no_daemon) { +#endif /* we have to init fdstat here. */ fd_open(0, FD_LOG, "stdin"); fd_open(1, FD_LOG, "stdout"); fd_open(2, FD_LOG, "stderr"); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainInitialize(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_RUNNING); +#endif + /* main loop */ for (;;) { if (do_reconfigure) { @@ -711,6 +835,9 @@ do_shutdown = 0; shutting_down = 1; serverConnectionsClose(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_STOP_PENDING); +#endif #if USE_DNSSERVERS dnsShutdown(); #else @@ -747,7 +874,11 @@ } } /* NOTREACHED */ +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } static void @@ -757,6 +888,11 @@ debug_log = stderr; pid = readPidFile(); if (pid > 1) { +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_signal_service) + WIN32_sendSignal(opt_send_signal); + else { +#endif if (kill(pid, opt_send_signal) && /* ignore permissions if just running check */ !(opt_send_signal == 0 && errno == EPERM)) { @@ -765,6 +901,9 @@ opt_send_signal, (int) pid, xstrerror()); exit(1); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + } +#endif } else { fprintf(stderr, "%s: ERROR: No running copy\n", appname); exit(1); @@ -773,6 +912,7 @@ exit(0); } +#ifndef _SQUID_MSWIN_ /* * This function is run when Squid is in daemon mode, just * before the parent forks and starts up the child process. @@ -809,6 +949,7 @@ } while (rpid != cpid); } } +#endif static int checkRunningPid(void) @@ -827,6 +968,7 @@ static void watch_child(char *argv[]) { +#ifndef _SQUID_MSWIN_ char *prog; int failcount = 0; time_t start; @@ -928,6 +1070,7 @@ sleep(3); } /* NOTREACHED */ +#endif } static void @@ -984,7 +1127,11 @@ errorClean(); #endif #if !XMALLOC_TRACE +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_INTERACTIVE) && (opt_no_daemon)) { +#else if (opt_no_daemon) { +#endif file_close(0); file_close(1); file_close(2); Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.41.6.3 retrieving revision 1.41.6.3.4.1 diff -u -r1.41.6.3 -r1.41.6.3.4.1 --- squid/src/protos.h 18 Feb 2002 15:01:19 -0000 1.41.6.3 +++ squid/src/protos.h 14 Mar 2002 20:23:44 -0000 1.41.6.3.4.1 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.41.6.3 2002/02/18 15:01:19 squidadm Exp $ + * $Id: protos.h,v 1.41.6.3.4.1 2002/03/14 20:23:44 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -787,6 +787,8 @@ extern void serverConnectionsClose(void); extern void shut_down(int); +extern void rotate_logs(int); +extern void reconfigure(int); extern void start_announce(void *unused); @@ -1202,7 +1204,11 @@ const char *const args[], const char *name, int *rfd, - int *wfd); + int *wfd +#ifdef _SQUID_MSWIN_ + , HANDLE * hIpc, pid_t * ppid +#endif +); /* CacheDigest */ extern CacheDigest *cacheDigestCreate(int capacity, int bpe); @@ -1324,8 +1330,25 @@ /* CygWin & Windows NT Port */ /* win32.c */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#ifdef USE_WIN32_SERVICE +extern int WIN32_Subsystem_Init(int *, char ***); +#else extern int WIN32_Subsystem_Init(void); +#endif +extern void WIN32_sendSignal(int); +extern void WIN32_Abort(int); extern void WIN32_Exit(void); +extern void WIN32_SetServiceCommandLine(void); +extern void WIN32_InstallService(void); +extern void WIN32_RemoveService(void); +#if defined(_SQUID_MSWIN_) && !defined(COMM_C) +#define comm_open(sock_type,proto,addr,port,flags,note) \ + comm_open((sock_type), \ + (sock_type) == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP, \ + (addr),(port),(flags),(note)) +#endif +extern int WIN32_getrusage(int, struct rusage *); +extern int WIN32_is_interface_down(const char *); #endif #endif /* SQUID_PROTOS_H */ Index: squid/src/squid.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/squid.h,v retrieving revision 1.13.6.2 retrieving revision 1.13.6.2.4.1 diff -u -r1.13.6.2 -r1.13.6.2.4.1 --- squid/src/squid.h 8 Jan 2002 05:19:18 -0000 1.13.6.2 +++ squid/src/squid.h 14 Mar 2002 20:23:45 -0000 1.13.6.2.4.1 @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.13.6.2 2002/01/08 05:19:18 squidadm Exp $ + * $Id: squid.h,v 1.13.6.2.4.1 2002/03/14 20:23:45 serassio Exp $ * * AUTHOR: Duane Wessels * @@ -211,7 +211,7 @@ #if HAVE_LIMITS_H #include #endif -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) #include #endif @@ -479,5 +479,13 @@ #define FD_READ_METHOD(fd, buf, len) (*fd_table[fd].read_method)(fd, buf, len) #define FD_WRITE_METHOD(fd, buf, len) (*fd_table[fd].write_method)(fd, buf, len) + +#ifndef IPPROTO_UDP +#define IPPROTO_UDP 0 +#endif + +#ifndef IPPROTO_TCP +#define IPPROTO_TCP 0 +#endif #endif /* SQUID_H */ Index: squid/src/stat.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/stat.c,v retrieving revision 1.13 retrieving revision 1.13.10.1 diff -u -r1.13 -r1.13.10.1 --- squid/src/stat.c 24 Oct 2001 09:42:13 -0000 1.13 +++ squid/src/stat.c 14 Mar 2002 20:23:45 -0000 1.13.10.1 @@ -1,6 +1,6 @@ /* - * $Id: stat.c,v 1.13 2001/10/24 09:42:13 squidadm Exp $ + * $Id: stat.c,v 1.13.10.1 2002/03/14 20:23:45 serassio Exp $ * * DEBUG: section 18 Cache Manager Statistics * AUTHOR: Harvest Derived @@ -459,6 +459,15 @@ runtime = 1.0; storeAppendPrintf(sentry, "Squid Object Cache: Version %s\n", version_string); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + storeAppendPrintf(sentry,"\nRunning as %s Windows System Service on %s\n", + WIN32_Service_name, WIN32_OS_string); + storeAppendPrintf(sentry,"Service command line is: %s\n", WIN32_Service_Command_Line); + } + else + storeAppendPrintf(sentry,"Running on %s\n",WIN32_OS_string); +#endif storeAppendPrintf(sentry, "Start Time:\t%s\n", mkrfc1123(squid_start.tv_sec)); storeAppendPrintf(sentry, "Current Time:\t%s\n", Index: squid/src/store_dir.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store_dir.c,v retrieving revision 1.19 retrieving revision 1.19.14.1 diff -u -r1.19 -r1.19.14.1 --- squid/src/store_dir.c 24 Oct 2001 09:42:14 -0000 1.19 +++ squid/src/store_dir.c 14 Mar 2002 20:23:45 -0000 1.19.14.1 @@ -1,6 +1,6 @@ /* - * $Id: store_dir.c,v 1.19 2001/10/24 09:42:14 squidadm Exp $ + * $Id: store_dir.c,v 1.19.14.1 2002/03/14 20:23:45 serassio Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels @@ -32,7 +32,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ - +#ifndef STORE_DIR_C +#define STORE_DIR_C #include "squid.h" #if HAVE_STATVFS @@ -78,13 +79,18 @@ { int i; SwapDir *sd; +#ifndef _SQUID_MSWIN_ pid_t pid; int status; +#endif for (i = 0; i < Config.cacheSwap.n_configured; i++) { +#ifndef _SQUID_MSWIN_ if (fork()) continue; +#endif sd = &Config.cacheSwap.swapDirs[i]; sd->newfs(sd); +#ifndef _SQUID_MSWIN_ exit(0); } do { @@ -94,6 +100,9 @@ pid = waitpid(-1, &status, 0); #endif } while (pid > 0 || (pid < 0 && errno == EINTR)); +#else + } +#endif } /* @@ -542,3 +551,4 @@ #endif return 0; } +#endif Index: squid/src/store_io.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store_io.c,v retrieving revision 1.3 retrieving revision 1.3.14.1 diff -u -r1.3 -r1.3.14.1 --- squid/src/store_io.c 24 Oct 2001 09:42:14 -0000 1.3 +++ squid/src/store_io.c 14 Mar 2002 20:23:45 -0000 1.3.14.1 @@ -1,3 +1,5 @@ +#ifndef STORE_IO_C +#define STORE_IO_C #include "squid.h" static struct { @@ -115,3 +117,4 @@ storeAppendPrintf(sentry, "create.create_fail %d\n", store_io_stats.create.create_fail); storeAppendPrintf(sentry, "create.success %d\n", store_io_stats.create.success); } +#endif Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.48 retrieving revision 1.48.6.1 diff -u -r1.48 -r1.48.6.1 --- squid/src/structs.h 1 Dec 2001 20:27:54 -0000 1.48 +++ squid/src/structs.h 14 Mar 2002 20:23:45 -0000 1.48.6.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.48 2001/12/01 20:27:54 squidadm Exp $ + * $Id: structs.h,v 1.48.6.1 2002/03/14 20:23:45 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -748,6 +748,9 @@ unsigned int type; u_short local_port; u_short remote_port; +#ifdef _SQUID_MSWIN_ + FILE * fbuf; +#endif struct in_addr local_addr; unsigned char tos; char ipaddr[16]; /* dotted decimal address of peer */ @@ -2051,6 +2054,10 @@ struct { int uses; } stats; +#ifdef _SQUID_MSWIN_ + HANDLE hIpc; + pid_t pid; +#endif }; Index: squid/src/tools.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/tools.c,v retrieving revision 1.19 retrieving revision 1.19.14.1 diff -u -r1.19 -r1.19.14.1 --- squid/src/tools.c 18 Nov 2001 01:15:42 -0000 1.19 +++ squid/src/tools.c 14 Mar 2002 20:23:46 -0000 1.19.14.1 @@ -1,6 +1,6 @@ /* - * $Id: tools.c,v 1.19 2001/11/18 01:15:42 squidadm Exp $ + * $Id: tools.c,v 1.19.14.1 2002/03/14 20:23:46 serassio Exp $ * * DEBUG: section 21 Misc Functions * AUTHOR: Harvest Derived @@ -305,6 +305,10 @@ void sigusr2_handle(int sig) { +#if defined(_SQUID_MSWIN_) && defined(_DEBUG) + do_debug = 1; +#endif +#if (defined(_SQUID_MSWIN_) && !defined(_DEBUG)) || !defined(_SQUID_MSWIN_) static int state = 0; /* no debug() here; bad things happen if the signal is delivered during _db_print() */ if (state == 0) { @@ -322,6 +326,7 @@ #endif state = 0; } +#endif #if !HAVE_SIGACTION signal(sig, sigusr2_handle); /* reinstall */ #endif @@ -415,6 +420,7 @@ void sig_child(int sig) { +#ifndef _SQUID_MSWIN_ #ifdef _SQUID_NEXT_ union wait status; #else @@ -435,6 +441,7 @@ } while (pid > 0 || (pid < 0 && errno == EINTR)); signal(sig, sig_child); #endif +#endif } const char * @@ -924,6 +931,9 @@ xrename(const char *from, const char *to) { debug(21, 2) ("xrename: renaming %s to %s\n", from, to); +#ifdef _SQUID_MSWIN_ + remove(to); +#endif if (0 == rename(from, to)) return 0; debug(21, errno == ENOENT ? 2 : 1) ("xrename: Cannot rename %s to %s: %s\n", @@ -966,9 +976,6 @@ char buf2[512]; char *nt = buf; char *lt = buf; -#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - char *systemroot = NULL; -#endif if (NULL == Config.etcHostsPath) return; if (0 == strcmp(Config.etcHostsPath, "none")) Index: squid/src/win32.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/win32.c,v retrieving revision 1.5 retrieving revision 1.5.14.1 diff -u -r1.5 -r1.5.14.1 --- squid/src/win32.c 18 Nov 2001 01:15:42 -0000 1.5 +++ squid/src/win32.c 14 Mar 2002 20:23:46 -0000 1.5.14.1 @@ -22,18 +22,189 @@ * */ +#ifndef WIN32_C +#define WIN32_C + #include "squid.h" /* This code compiles only CygWin & Windows NT Port */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) #include +#ifdef _SQUID_MSWIN_ +#if HAVE_WIN32_PSAPI +#include +#endif +#include +#endif static unsigned int GetOSVersion(); +void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int); +static int WIN32_create_key(void); +static void WIN32_build_argv (char *); +void WINAPI SquidMain(DWORD, char **); + +/* The following code section is part of an EXPERIMENTAL native */ +/* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */ +#if defined(_SQUID_MSWIN_) +static int Win32SockInit(void); +static void Win32SockCleanup(void); +#endif /* End native Windows NT EXPERIMENTAL PORT */ + +static SERVICE_STATUS svcStatus; +static SERVICE_STATUS_HANDLE svcHandle; +static int WIN32_argc; +static char ** WIN32_argv; +static char * WIN32_module_name; + +#define VENDOR "GNU" +#if defined(_SQUID_MSWIN_) +#define SOFTWARENAME "SquidNT" +#else +#define SOFTWARENAME "Squid" +#endif +#define WIN32_VERSION "2.5" +#define COMMANDLINE "CommandLine" +#define CONFIGFILE "ConfigFile" +#undef ChangeServiceConfig2 +typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID); +#ifdef UNICODE +#define CHANGESERVICECONFIG2 "ChangeServiceConfig2W" +#else +#define CHANGESERVICECONFIG2 "ChangeServiceConfig2A" +#endif +static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } }; +static SERVICE_DESCRIPTION Squid_ServiceDescription = { SOFTWARENAME " " VERSION " WWW Proxy Server" }; +static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { 0, NULL, NULL, 1, Squid_SCAction }; +static char REGKEY[256]="SOFTWARE\\"VENDOR"\\"SOFTWARENAME"\\"WIN32_VERSION"\\"; +static char *keys[] = { + "SOFTWARE", /* key[0] */ + VENDOR, /* key[1] */ + SOFTWARENAME, /* key[2] */ + WIN32_VERSION, /* key[3] */ + NULL, /* key[4] */ + NULL /* key[5] */ +}; /* ====================================================================== */ /* LOCAL FUNCTIONS */ /* ====================================================================== */ +static int +WIN32_create_key(void) +{ + int index; + HKEY hKey; + HKEY hKeyNext; + int retval; + long rv; + + hKey = HKEY_LOCAL_MACHINE; + index = 0; + retval = 0; + + /* Walk the tree, creating at each stage if necessary */ + while (keys[index]) { + unsigned long result; + rv = RegCreateKeyEx(hKey, keys[index], /* subkey */ + 0, /* reserved */ + NULL, /* class */ + REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCreateKeyEx(%s),%d\n", keys[index], (int) rv); + retval = -4; + } + /* Close the old key */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey %d\n", (int) rv); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + if (retval) { + break; + } + hKey = hKeyNext; + index++; + } + if (keys[index] == NULL) { + /* Close the final key we opened, if we walked the entire + * tree + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey %d\n", (int) rv); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + } + return retval; +} + +static int +WIN32_StoreKey(const char *key, DWORD type, unsigned char *value, + int value_size) +{ + long rv; + HKEY hKey; + int retval; + + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); + if (rv == ERROR_FILE_NOT_FOUND) { + /* Key could not be opened -- try to create it + */ + if (WIN32_create_key() < 0) { + /* Creation failed (error already reported) */ + return -4; + } + /* Now it has been created we should be able to open it + */ + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); + if (rv == ERROR_FILE_NOT_FOUND) { + debug(1, 1) ("Registry does not contain key %s after creation", + REGKEY); + return -1; + } + } + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv); + return -4; + } + /* Now set the value and data */ + rv = RegSetValueEx(hKey, key, /* value key name */ + 0, /* reserved */ + type, /* type */ + value, /* value data */ + (DWORD) value_size); /* for size of "value" */ + retval = 0; /* Return value */ + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegQueryValueEx(key %s),%d\n", key, (int) rv); + retval = -4; + } else { + debug(1, 1) ("Registry stored HKLM\\%s\\%s value %s\n", + REGKEY, + key, + type == REG_SZ ? value : (unsigned char *) "(not displayable)"); + } + /* Make sure we close the key even if there was an error storing + * the data + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv); + if (retval == 0) { + /* Keep error status from RegQueryValueEx, if any */ + retval = -4; + } + } + return retval; +} + static unsigned int GetOSVersion() { @@ -83,24 +254,546 @@ return _WIN_OS_UNKNOWN; } +/* Build argv, argc from string passed from Windows. */ +static void WIN32_build_argv(char *cmd) +{ + int argvlen = 0; + char *word; + + WIN32_argc = 1; + WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *)); + WIN32_argv[0]=xstrdup(WIN32_module_name); +/* Scan command line until there is nothing left. */ + while (*cmd) { + /* Ignore spaces */ + if (xisspace(*cmd)) { + cmd++; + continue; + } + /* Found the beginning of an argument. */ + word = cmd; + while (*cmd) { + cmd++; /* Skip over this character */ + if (xisspace(*cmd)) /* End of argument if space */ + break; + } + if (*cmd) + *cmd++ = '\0'; /* Terminate `word' */ + /* See if we need to allocate more space for argv */ + if (WIN32_argc >= argvlen) { + argvlen = WIN32_argc + 1; + WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *)); + } + /* Add word to argv file. */ + WIN32_argv[WIN32_argc++] = word; + } + WIN32_argv[WIN32_argc] = NULL; +} + /* ====================================================================== */ /* PUBLIC FUNCTIONS */ /* ====================================================================== */ void +WIN32_Abort(int sig) +{ +#ifdef USE_WIN32_SERVICE + svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + svcStatus.dwServiceSpecificExitCode = 1; +#endif + WIN32_Exit(); +} + +void WIN32_Exit() { +#ifdef _SQUID_MSWIN_ + Win32SockCleanup(); +#endif +#ifdef USE_WIN32_SERVICE + svcStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(svcHandle, &svcStatus); +#endif _exit(0); } -int -WIN32_Subsystem_Init() +#ifdef USE_WIN32_SERVICE +int WIN32_Subsystem_Init(int * argc, char *** argv) +#else +int WIN32_Subsystem_Init() +#endif { WIN32_OS_version = GetOSVersion(); if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S)) return 1; if (atexit(WIN32_Exit) != 0) return 1; +#ifdef USE_WIN32_SERVICE + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + char path[512]; + HKEY hndKey; + if (signal(SIGABRT, WIN32_Abort) == SIG_ERR) + return 1; + /* Register the service Handler function */ + svcHandle = + RegisterServiceCtrlHandler(WIN32_Service_name, + WIN32_svcHandler); + if (svcHandle == 0) + return 1; + /* Set Service Staus to SERVICE_START_PENDING */ + svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + svcStatus.dwCurrentState = SERVICE_START_PENDING; + svcStatus.dwControlsAccepted = + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwServiceSpecificExitCode = 0; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + SetServiceStatus(svcHandle, &svcStatus); + /* Set Process work dir to directory cointaining squid.exe */ + GetModuleFileName(NULL, path, 512); + WIN32_module_name=xstrdup(path); + path[strlen(path) - 10] = '\0'; + if (SetCurrentDirectory(path) == 0) + return 1; + safe_free(ConfigFile); + /* get config file from Windows Registry */ + if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) { + DWORD Type = 0; + DWORD Size = 0; + LONG Result; + Result = + RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size); + if (Result == ERROR_SUCCESS && Size) { + ConfigFile = xmalloc(Size); + RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, ConfigFile, + &Size); + } else + ConfigFile = xstrdup(DefaultConfigFile); + Size = 0; + Type = 0; + Result = + RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size); + if (Result == ERROR_SUCCESS && Size) { + WIN32_Service_Command_Line = xmalloc(Size); + RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, WIN32_Service_Command_Line, + &Size); + } else + WIN32_Service_Command_Line = xstrdup(""); + RegCloseKey(hndKey); + } else { + ConfigFile = xstrdup(DefaultConfigFile); + WIN32_Service_Command_Line = xstrdup(""); + } + WIN32_build_argv(WIN32_Service_Command_Line); + *argc = WIN32_argc; + *argv = WIN32_argv; + } +#endif +#ifdef _SQUID_MSWIN_ + Win32SockInit(); +#endif + return 0; +} + +#ifdef USE_WIN32_SERVICE +void +WIN32_svcstatusupdate(DWORD svcstate) +{ + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + svcStatus.dwCheckPoint++; + svcStatus.dwCurrentState = svcstate; + SetServiceStatus(svcHandle, &svcStatus); + } +} + +VOID WINAPI +WIN32_svcHandler(DWORD Opcode) +{ + DWORD status; + + switch (Opcode) { + case _WIN_SQUID_SERVICE_CONTROL_STOP: + case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN: +/* Do whatever it takes to stop here. */ + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwCurrentState = SERVICE_STOP_PENDING; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + shut_down(SIGTERM); + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + debug(1, 1) ("Leaving Squid service \n"); + return; + case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE: +/* Fall through to send current status. */ + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + break; + case _WIN_SQUID_SERVICE_CONTROL_ROTATE: + rotate_logs(SIGUSR1); + break; + case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE: + reconfigure(SIGHUP); + break; + case _WIN_SQUID_SERVICE_CONTROL_DEBUG: + sigusr2_handle(SIGUSR2); + break; + case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT: +/* Do whatever it takes to stop here. */ + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwCurrentState = SERVICE_STOP_PENDING; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + shut_down(SIGINT); + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + debug(1, 1) ("Leaving Squid service \n"); + break; + default: + debug(1, 1) ("Unrecognized opcode %ld\n", Opcode); + } + return; +} + +void +WIN32_RemoveService() +{ + SC_HANDLE schService; + SC_HANDLE schSCManager; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) + debug(1, 1) ("OpenSCManager failed"); + else { + schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS); + if (schService == NULL) + debug(1, 1) ("OpenService failed"); + /* Could not open the service */ + else { + /* try to stop the service */ + if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP, + &svcStatus)) { + sleep(1); + while (QueryServiceStatus(schService, &svcStatus)) { + if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) + sleep(1); + else + break; + } + } + /* now remove the service */ + if (DeleteService(schService) == 0) + fprintf(stderr,"DeleteService failed.\n"); + else + printf("Service %s deleted successfully.\n", + WIN32_Service_name); + CloseServiceHandle(schService); + } + CloseServiceHandle(schSCManager); + } +} + +void +WIN32_SetServiceCommandLine() +{ + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + /* Now store the Service Command Line in the registry */ + WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1); +} + +void +WIN32_InstallService() +{ + SC_HANDLE schService; + SC_HANDLE schSCManager; + char ServicePath[512]; + char szPath[512]; + int lenpath; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) { + debug(1, 1) ("Can't get executable path"); + exit(1); + } + snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name); + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) { + debug(1, 1) ("OpenSCManager failed"); + exit(1); + } + else { + schService = CreateService(schSCManager, /* SCManager database */ + WIN32_Service_name, /* name of service */ + WIN32_Service_name, /* name to display */ + SERVICE_ALL_ACCESS, /* desired access */ + SERVICE_WIN32_OWN_PROCESS, /* service type */ + SERVICE_AUTO_START, /* start type */ + SERVICE_ERROR_NORMAL, /* error control type */ + (const char *) szPath, /* service's binary */ + NULL, /* no load ordering group */ + NULL, /* no tag identifier */ + "Tcpip\0AFD\0", /* dependencies */ + NULL, /* LocalSystem account */ + NULL); /* no password */ + if (schService) { + if ((WIN32_OS_version == _WIN_OS_WIN2K) || (WIN32_OS_version == _WIN_OS_WINXP)) + { + HMODULE ADVAPI32Handle; + PFChangeServiceConfig2 ChangeServiceConfig2; + DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION; + + ADVAPI32Handle = GetModuleHandle("advapi32"); + ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2); + ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription); + dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS; + ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions); + } + CloseServiceHandle(schService); + /* Now store the config file location in the registry */ + if (!ConfigFile) + ConfigFile = xstrdup(DefaultConfigFile); + WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1); + printf("Squid Cache version %s for %s\n", version_string, + CONFIG_HOST_TYPE); + printf("installed successfully as %s Windows System Service.\n", + WIN32_Service_name); + printf + ("To run, start it from the Services Applet of Control Panel.\n"); + printf("Don't forget to edit squid.conf before starting it.\n\n"); + } else { + debug(1, 1) ("CreateService failed"); + exit(1); + } + CloseServiceHandle(schSCManager); + } +} + +void +WIN32_sendSignal(int WIN32_signal) +{ + SERVICE_STATUS ssStatus; + DWORD fdwAccess, fdwControl; + SC_HANDLE schService; + SC_HANDLE schSCManager; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) { + debug(1, 1) ("OpenSCManager failed"); + exit(1); + } + /* The required service object access depends on the control. */ + switch (WIN32_signal) { + case 0: /* SIGNULL */ + fdwAccess = SERVICE_INTERROGATE; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE; + break; + case SIGUSR1: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE; + break; + case SIGUSR2: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG; + break; + case SIGHUP: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE; + break; + case SIGTERM: + fdwAccess = SERVICE_STOP; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP; + break; + case SIGINT: + case SIGKILL: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT; + break; + default: + exit(1); + } + /* Open a handle to the service. */ + schService = OpenService(schSCManager, /* SCManager database */ + WIN32_Service_name, /* name of service */ + fdwAccess); /* specify access */ + if (schService == NULL) { + fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname, + WIN32_Service_name); + exit(1); + } else { + /* Send a control value to the service. */ + if (!ControlService(schService, /* handle of service */ + fdwControl, /* control value to send */ + &ssStatus)) { /* address of status info */ + fprintf(stderr, "%s: ERROR: Could not Control Service %s\n", + appname, WIN32_Service_name); + exit(1); + } else { + /* Print the service status. */ + printf("\nStatus of %s Service:\n", WIN32_Service_name); + printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType); + printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState); + printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted); + printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode); + printf(" Service Specific Exit Code: %ld\n", + ssStatus.dwServiceSpecificExitCode); + printf(" Check Point: %ld\n", ssStatus.dwCheckPoint); + printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint); + } + CloseServiceHandle(schService); + } + CloseServiceHandle(schSCManager); +} + +int main(int argc, char **argv) +{ + SERVICE_TABLE_ENTRY DispatchTable[] = { + {NULL, SquidMain}, + {NULL, NULL} + }; + char *c; + + if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)){ + WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE; + if (!(c=strchr(argv[1],':'))){ + fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]); + return 1; + } + WIN32_Service_name = xstrdup(c+1); + DispatchTable[0].lpServiceName=WIN32_Service_name; + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + if (!StartServiceCtrlDispatcher(DispatchTable)) { + fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", + GetLastError()); + return 1; + } + } else { + WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE; + SquidMain(argc, argv); + } return 0; } #endif + +/* The following code section is part of an EXPERIMENTAL native */ +/* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */ + +#if defined(_SQUID_MSWIN_) +static int s_iInitCount = 0; + +int WIN32_getrusage(int who, struct rusage *usage) +{ +#if HAVE_WIN32_PSAPI + if ((WIN32_OS_version == _WIN_OS_WINNT) || (WIN32_OS_version == _WIN_OS_WIN2K) + || (WIN32_OS_version == _WIN_OS_WINXP)) + { + /* On Windows NT/2000 call PSAPI.DLL for process Memory */ + /* informations -- Guido Serassio */ + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ, + FALSE, GetCurrentProcessId()); + { + /* Microsoft Visual C++ doesn't have getrusage function, */ + /* so we get process CPU time information from PSAPI.DLL. */ + FILETIME ftCreate, ftExit, ftKernel, ftUser; + if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) + { + LONGLONG tUser64 = (*(LONGLONG *)&ftUser / 10); + LONGLONG tKernel64 = (*(LONGLONG *)&ftKernel / 10); + usage->ru_utime.tv_sec =(long)(tUser64 / 1000000); + usage->ru_stime.tv_sec =(long)(tKernel64 / 1000000); + usage->ru_utime.tv_usec =(long)(tUser64 % 1000000); + usage->ru_stime.tv_usec =(long)(tKernel64 % 1000000); + } + else + { + CloseHandle( hProcess ); + return -1; + } + } + if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) + { + usage->ru_maxrss=(DWORD)(pmc.WorkingSetSize /1024); + usage->ru_majflt=pmc.PageFaultCount; + } + else + { + CloseHandle( hProcess ); + return -1; + } + CloseHandle( hProcess ); + } +#endif + return 0; +} + +static int Win32SockInit(void) +{ + int iVersionRequested; + WSADATA wsaData; + int err; + + if (s_iInitCount > 0) { + s_iInitCount++; + return (0); + } + else if (s_iInitCount < 0) + return (s_iInitCount); + /* s_iInitCount == 0. Do the initailization */ + iVersionRequested = MAKEWORD(2, 0); + err = WSAStartup((WORD) iVersionRequested, &wsaData); + if (err) { + s_iInitCount = -1; + return (s_iInitCount); + } + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 0) { + s_iInitCount = -2; + WSACleanup(); + return (s_iInitCount); + } + debug(1,1)("Windows sockets initialised"); + s_iInitCount++; + return (s_iInitCount); +} + +static void Win32SockCleanup(void) +{ + if (--s_iInitCount == 0) + WSACleanup(); + return; +} +#endif /* End native Windows NT EXPERIMENTAL PORT */ +#endif + +#endif /* WIN32_C */ --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/Makefile Wed Feb 14 00:57:26 2007 @@ -0,0 +1,241 @@ +# Makefile.in generated automatically by automake 1.5 from Makefile.am. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = ../../.. + +prefix = c:/squid +exec_prefix = ${prefix} + +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +libexecdir = ${exec_prefix}/libexec +datadir = ${prefix}/share +sysconfdir = ${prefix}/etc +sharedstatedir = ${prefix}/com +localstatedir = ${prefix}/var +libdir = ${exec_prefix}/lib +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include +pkgdatadir = $(datadir)/squid +pkglibdir = $(libdir)/squid +pkgincludedir = $(includedir)/squid +top_builddir = ../../.. + +ACLOCAL = ${SHELL} /cygdrive/c/work/cygwin-svc/cfgaux/missing --run aclocal +AUTOCONF = ${SHELL} /cygdrive/c/work/cygwin-svc/cfgaux/missing --run autoconf +AUTOMAKE = ${SHELL} /cygdrive/c/work/cygwin-svc/cfgaux/missing --run automake +AUTOHEADER = ${SHELL} /cygdrive/c/work/cygwin-svc/cfgaux/missing --run autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +INSTALL_HEADER = $(INSTALL_DATA) +transform = s,x,x, +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-cygwin +AIOLIB = +AMTAR = ${SHELL} /cygdrive/c/work/cygwin-svc/cfgaux/missing --run tar +AR = /usr/bin/ar +AR_R = /usr/bin/ar r +AUTH_LIBS = libbasic.a libntlm.a +AUTH_MODULES = basic ntlm +AUTH_OBJS = auth/libbasic.a auth/libntlm.a +AWK = gawk +BASIC_AUTH_HELPERS = win32_locallogon +CC = gcc +CPP = gcc -E +CRYPTLIB = -lcrypt +CXX = @CXX@ +DEPDIR = .deps +DIGEST_AUTH_HELPERS = +DLLIB = +ERR_DEFAULT_LANGUAGE = English +ERR_LANGUAGES = Bulgarian Czech Danish Dutch English Estonian Finnish French German Hungarian Italian Japanese Korean Polish Portuguese Romanian Russian-1251 Russian-koi8-r Serbian Simplify_Chinese Slovak Spanish Swedish Traditional_Chinese Turkish +EXEEXT = .exe +FALSE = /usr/bin/false +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +LIBDLMALLOC = +LIBREGEX = +LIB_MALLOC = +LN = /usr/bin/ln +LN_S = ln -s +MAINT = # +MKDIR = /usr/bin/mkdir +MV = /usr/bin/mv +NTLM_AUTH_HELPERS = NTLMSSP +OBJEXT = o +OPT_DISKD_EXE = +OPT_DNSSERVER_EXE = +OPT_PINGER = +OPT_PINGER_EXE = +PACKAGE = squid +PERL = /usr/bin/perl +PTHREADLIB = -lpthread +RANLIB = ranlib +REGEXLIB = -lregex +REPL_LIBS = liblru.a +REPL_OBJS = repl/liblru.a +REPL_POLICIES = lru +RM = /usr/bin/rm +SH = /usr/bin/sh +SNMPLIB = -L../snmplib -lsnmp +SQUID_AIO_LIB = +SQUID_PTHREAD_LIB = +SSLLIB = +STORE_LIBS = libufs.a +STORE_MODULES = ufs +STORE_MODULE_SUBDIRS = +STORE_OBJS = fs/libufs.a +TRUE = /usr/bin/true +VERSION = 2.6-DEVEL +XTRA_LIBS = -lm +XTRA_OBJS = +am__include = include +am__quote = +install_sh = /cygdrive/c/work/cygwin-svc/cfgaux/install-sh +makesnmplib = snmplib +subdir = src/fs/awin32 +mkinstalldirs = $(SHELL) $(top_srcdir)/cfgaux/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/autoconf.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = Makefile.am Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: # Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/fs/awin32/Makefile +Makefile: # $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && \ + CONFIG_HEADERS= CONFIG_LINKS= \ + CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status +uninstall-info-am: +tags: TAGS +TAGS: + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + $(mkinstalldirs) "$(distdir)/$$dir"; \ + fi; \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic uninstall uninstall-am uninstall-info-am + + +all clean: + @cd .. && $(MAKE) $(MFLAGS) awin32/$@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/Makefile.am Wed Feb 14 00:57:26 2007 @@ -0,0 +1,2 @@ +all clean: + @cd .. && $(MAKE) $(MFLAGS) awin32/$@ --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/Makefile.in Wed Feb 14 00:57:26 2007 @@ -0,0 +1,241 @@ +# Makefile.in generated automatically by automake 1.5 from Makefile.am. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AIOLIB = @AIOLIB@ +AMTAR = @AMTAR@ +AR = @AR@ +AR_R = @AR_R@ +AUTH_LIBS = @AUTH_LIBS@ +AUTH_MODULES = @AUTH_MODULES@ +AUTH_OBJS = @AUTH_OBJS@ +AWK = @AWK@ +BASIC_AUTH_HELPERS = @BASIC_AUTH_HELPERS@ +CC = @CC@ +CPP = @CPP@ +CRYPTLIB = @CRYPTLIB@ +CXX = @CXX@ +DEPDIR = @DEPDIR@ +DIGEST_AUTH_HELPERS = @DIGEST_AUTH_HELPERS@ +DLLIB = @DLLIB@ +ERR_DEFAULT_LANGUAGE = @ERR_DEFAULT_LANGUAGE@ +ERR_LANGUAGES = @ERR_LANGUAGES@ +EXEEXT = @EXEEXT@ +FALSE = @FALSE@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LIBDLMALLOC = @LIBDLMALLOC@ +LIBREGEX = @LIBREGEX@ +LIB_MALLOC = @LIB_MALLOC@ +LN = @LN@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MKDIR = @MKDIR@ +MV = @MV@ +NTLM_AUTH_HELPERS = @NTLM_AUTH_HELPERS@ +OBJEXT = @OBJEXT@ +OPT_DISKD_EXE = @OPT_DISKD_EXE@ +OPT_DNSSERVER_EXE = @OPT_DNSSERVER_EXE@ +OPT_PINGER = @OPT_PINGER@ +OPT_PINGER_EXE = @OPT_PINGER_EXE@ +PACKAGE = @PACKAGE@ +PERL = @PERL@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +REGEXLIB = @REGEXLIB@ +REPL_LIBS = @REPL_LIBS@ +REPL_OBJS = @REPL_OBJS@ +REPL_POLICIES = @REPL_POLICIES@ +RM = @RM@ +SH = @SH@ +SNMPLIB = @SNMPLIB@ +SQUID_AIO_LIB = @SQUID_AIO_LIB@ +SQUID_PTHREAD_LIB = @SQUID_PTHREAD_LIB@ +SSLLIB = @SSLLIB@ +STORE_LIBS = @STORE_LIBS@ +STORE_MODULES = @STORE_MODULES@ +STORE_MODULE_SUBDIRS = @STORE_MODULE_SUBDIRS@ +STORE_OBJS = @STORE_OBJS@ +TRUE = @TRUE@ +VERSION = @VERSION@ +XTRA_LIBS = @XTRA_LIBS@ +XTRA_OBJS = @XTRA_OBJS@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +makesnmplib = @makesnmplib@ +subdir = src/fs/awin32 +mkinstalldirs = $(SHELL) $(top_srcdir)/cfgaux/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/autoconf.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = Makefile.am Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/fs/awin32/Makefile +Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && \ + CONFIG_HEADERS= CONFIG_LINKS= \ + CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status +uninstall-info-am: +tags: TAGS +TAGS: + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + $(mkinstalldirs) "$(distdir)/$$dir"; \ + fi; \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic uninstall uninstall-am uninstall-info-am + + +all clean: + @cd .. && $(MAKE) $(MFLAGS) awin32/$@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/aiops.c Wed Feb 14 00:57:26 2007 @@ -0,0 +1,1021 @@ +/* + * $Id: aiops.c,v 1.1.62.1 2002/03/14 20:23:47 serassio Exp $ + * + * DEBUG: section 43 AIOPS + * AUTHOR: Stewart Forster + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include +#include "store_asyncufs.h" + + +#include +#include +#include +#include +#include +#include +#include + +#define RIDICULOUS_LENGTH 4096 + +enum _squidaio_thread_status { + _THREAD_STARTING = 0, + _THREAD_WAITING, + _THREAD_BUSY, + _THREAD_FAILED, + _THREAD_DONE +}; +typedef enum _squidaio_thread_status squidaio_thread_status; + +enum _squidaio_request_type { + _AIO_OP_NONE = 0, + _AIO_OP_OPEN, + _AIO_OP_READ, + _AIO_OP_WRITE, + _AIO_OP_CLOSE, + _AIO_OP_UNLINK, + _AIO_OP_TRUNCATE, + _AIO_OP_OPENDIR, + _AIO_OP_STAT +}; +typedef enum _squidaio_request_type squidaio_request_type; + +typedef struct squidaio_request_t { + struct squidaio_request_t *next; + squidaio_request_type request_type; + int cancelled; + char *path; + int oflag; + mode_t mode; + int fd; + char *bufferp; + char *tmpbufp; + int buflen; + off_t offset; + int whence; + int ret; + int err; + struct stat *tmpstatp; + struct stat *statp; + squidaio_result_t *resultp; +} squidaio_request_t; + +typedef struct squidaio_request_queue_t { + HANDLE mutex; /* pthread_mutex_t mutex; */ + HANDLE cond; /*pthread_cond_t cond; */ /* See Event objects */ + squidaio_request_t *volatile head; + squidaio_request_t *volatile *volatile tailp; + unsigned long requests; + unsigned long blocked; /* main failed to lock the queue */ +} squidaio_request_queue_t; + +typedef struct squidaio_thread_t squidaio_thread_t; +struct squidaio_thread_t { + squidaio_thread_t *next; + HANDLE thread; /* pthread_t thread; */ + DWORD dwThreadId; /* thread ID */ + squidaio_thread_status status; + struct squidaio_request_t *current_req; + unsigned long requests; +}; + +int squidaio_cancel(squidaio_result_t *); +int squidaio_open(const char *, int, mode_t, squidaio_result_t *); +int squidaio_read(int, char *, int, off_t, int, squidaio_result_t *); +int squidaio_write(int, char *, int, off_t, int, squidaio_result_t *); +int squidaio_close(int, squidaio_result_t *); +int squidaio_unlink(const char *, squidaio_result_t *); +int squidaio_truncate(const char *, off_t length, squidaio_result_t *); +int squidaio_opendir(const char *, squidaio_result_t *); +squidaio_result_t *squidaio_poll_done(); +int squidaio_sync(void); + +static void squidaio_init(void); +static void squidaio_queue_request(squidaio_request_t *); +static void squidaio_cleanup_request(squidaio_request_t *); +/* static void *squidaio_thread_loop(void *); */ +static DWORD WINAPI squidaio_thread_loop( LPVOID lpParam ); +static void squidaio_do_open(squidaio_request_t *); +static void squidaio_do_read(squidaio_request_t *); +static void squidaio_do_write(squidaio_request_t *); +static void squidaio_do_close(squidaio_request_t *); +static void squidaio_do_stat(squidaio_request_t *); +static void squidaio_do_unlink(squidaio_request_t *); +static void squidaio_do_truncate(squidaio_request_t *); +#if AIO_OPENDIR +static void *squidaio_do_opendir(squidaio_request_t *); +#endif +static void squidaio_debug(squidaio_request_t *); +static void squidaio_poll_queues(void); + +static squidaio_thread_t *threads = NULL; +static int squidaio_initialised = 0; + + +#define AIO_LARGE_BUFS 16384 +#define AIO_MEDIUM_BUFS AIO_LARGE_BUFS >> 1 +#define AIO_SMALL_BUFS AIO_LARGE_BUFS >> 2 +#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3 +#define AIO_MICRO_BUFS 128 + +static MemPool *squidaio_large_bufs = NULL; /* 16K */ +static MemPool *squidaio_medium_bufs = NULL; /* 8K */ +static MemPool *squidaio_small_bufs = NULL; /* 4K */ +static MemPool *squidaio_tiny_bufs = NULL; /* 2K */ +static MemPool *squidaio_micro_bufs = NULL; /* 128K */ + +static int request_queue_len = 0; +static MemPool *squidaio_request_pool = NULL; +static MemPool *squidaio_thread_pool = NULL; +static squidaio_request_queue_t request_queue; +static struct { + squidaio_request_t *head, **tailp; +} request_queue2 = { + + NULL, &request_queue2.head +}; +static squidaio_request_queue_t done_queue; +static struct { + squidaio_request_t *head, **tailp; +} done_requests = { + + NULL, &done_requests.head +}; +/* static pthread_attr_t globattr; The attributes of a created thread */ +/*static struct sched_param globsched; */ +/* static pthread_t main_thread; */ +static HANDLE main_thread; + +static MemPool * +squidaio_get_pool(int size) +{ + MemPool *p; + if (size <= AIO_LARGE_BUFS) { + if (size <= AIO_MICRO_BUFS) + p = squidaio_micro_bufs; + else if (size <= AIO_TINY_BUFS) + p = squidaio_tiny_bufs; + else if (size <= AIO_SMALL_BUFS) + p = squidaio_small_bufs; + else if (size <= AIO_MEDIUM_BUFS) + p = squidaio_medium_bufs; + else + p = squidaio_large_bufs; + } else + p = NULL; + return p; +} + +static void * +squidaio_xmalloc(int size) +{ + void *p; + MemPool *pool; + + if ((pool = squidaio_get_pool(size)) != NULL) { + p = memPoolAlloc(pool); + } else + p = xmalloc(size); + + return p; +} + +static char * +squidaio_xstrdup(const char *str) +{ + char *p; + int len = strlen(str) + 1; + + p = squidaio_xmalloc(len); + strncpy(p, str, len); + + return p; +} + +static void +squidaio_xfree(void *p, int size) +{ + MemPool *pool; + + if ((pool = squidaio_get_pool(size)) != NULL) { + memPoolFree(pool, p); + } else + xfree(p); +} + +static void +squidaio_xstrfree(char *str) +{ + MemPool *pool; + int len = strlen(str) + 1; + + if ((pool = squidaio_get_pool(len)) != NULL) { + memPoolFree(pool, str); + } else + xfree(str); +} + +static void +squidaio_init(void) +{ + int i; + squidaio_thread_t *threadp; + + if (squidaio_initialised) + return; + + if (!DuplicateHandle(GetCurrentProcess(), /* pseudo handle, don't close */ + GetCurrentThread(), /* pseudo handle to copy */ + GetCurrentProcess(), /* pseudo handle, don't close */ + &main_thread, + 0, /* required access */ + FALSE, /* child process's don't inherit the handle */ + DUPLICATE_SAME_ACCESS)) { + /* spit errors */ + fatal("couldn't get current thread handle\n"); + } + /* FIXME: where do we CloseHandle the main_thread ?*/ +#if 0 +/* FIXME set the current thread to priority 1 */ +#if HAVE_PTHREAD_SETSCHEDPARAM + pthread_setschedparam(main_thread, SCHED_OTHER, &globsched); +#endif +/* FIXME set new threads to priority 2 + globsched.sched_priority = 2; +#if HAVE_PTHREAD_ATTR_SETSCHEDPARAM + pthread_attr_setschedparam(&globattr, &globsched); +#endif +*/ +#endif + + /* Initialize request queue */ + if ((request_queue.mutex=CreateMutex( NULL, /* no inheritance */ + FALSE, /* start unowned (as per mutex_init) */ + NULL /* no name */ ) + )==NULL) { + fatal("failed to create mutex\n"); + } + if ((request_queue.cond=CreateEvent( NULL, /* no inheritance */ + FALSE, /* auto signal reset - which I think is pthreads like ? */ + FALSE, /* start non signaled */ + NULL /* no name */ ) + )==NULL) { + fatal("failed to create condition event variable.\n"); + } + request_queue.head = NULL; + request_queue.tailp = &request_queue.head; + request_queue.requests = 0; + request_queue.blocked = 0; + + /* Initialize done queue */ + if ((done_queue.mutex=CreateMutex( NULL, /* no inheritance */ + FALSE, /* start unowned (as per mutex_init) */ + NULL /* no name */ ) + )==NULL) { + fatal("failed to create mutex\n"); + } + if ((done_queue.cond=CreateEvent( NULL, /* no inheritance */ + TRUE, /* manually signaled - which I think is pthreads like ? */ + FALSE, /* start non signaled */ + NULL /* no name */ ) + )==NULL) { + fatal("failed to create condition event variable.\n"); + } + done_queue.head = NULL; + done_queue.tailp = &done_queue.head; + done_queue.requests = 0; + done_queue.blocked = 0; + + /* Create threads and get them to sit in their wait loop */ + squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t)); + for (i = 0; i < NUMTHREADS; i++) { + threadp = memPoolAlloc(squidaio_thread_pool); + threadp->status = _THREAD_STARTING; + threadp->current_req = NULL; + threadp->requests = 0; + threadp->next = threads; + threads = threadp; + if ((threadp->thread = CreateThread( + NULL, // no security attributes + 0, // use default stack size + squidaio_thread_loop, // thread function + threadp, // argument to thread function + 0, // use default creation flags + &(threadp->dwThreadId)) // returns the thread identifier + )==NULL) { + fprintf(stderr, "Thread creation failed\n"); + threadp->status = _THREAD_FAILED; + continue; + } + } + + /* Create request pool */ + squidaio_request_pool = memPoolCreate("aio_request", sizeof(squidaio_request_t)); + squidaio_large_bufs = memPoolCreate("squidaio_large_bufs", AIO_LARGE_BUFS); + squidaio_medium_bufs = memPoolCreate("squidaio_medium_bufs", AIO_MEDIUM_BUFS); + squidaio_small_bufs = memPoolCreate("squidaio_small_bufs", AIO_SMALL_BUFS); + squidaio_tiny_bufs = memPoolCreate("squidaio_tiny_bufs", AIO_TINY_BUFS); + squidaio_micro_bufs = memPoolCreate("squidaio_micro_bufs", AIO_MICRO_BUFS); + + squidaio_initialised = 1; +} + + +static DWORD WINAPI +squidaio_thread_loop( LPVOID lpParam ) +{ + squidaio_thread_t *threadp = lpParam; + squidaio_request_t *request; + HANDLE cond; /* local copy of the event queue because win32 event handles + * don't atomically release the mutex as cond variables do. */ + +#if 0 +/* sigset_t new; */ + /* + * Does WIN32 have this problem? + */ + + /* + * Make sure to ignore signals which may possibly get sent to + * the parent squid thread. Causes havoc with mutex's and + * condition waits otherwise + */ + + sigemptyset(&new); + sigaddset(&new, SIGPIPE); + sigaddset(&new, SIGCHLD); +#ifdef _SQUID_LINUX_THREADS_ + sigaddset(&new, SIGQUIT); + sigaddset(&new, SIGTRAP); +#else + sigaddset(&new, SIGUSR1); + sigaddset(&new, SIGUSR2); +#endif + sigaddset(&new, SIGHUP); + sigaddset(&new, SIGTERM); + sigaddset(&new, SIGINT); + sigaddset(&new, SIGALRM); + pthread_sigmask(SIG_BLOCK, &new, NULL); +#endif /* 0 */ + + /* lock the thread info */ + if (WAIT_FAILED == WaitForSingleObject( + request_queue.mutex, // handle to object + INFINITE // time-out interval + )) { + /* wait failed.... what to do ? */ + } + /* duplicate the handle */ + if (!DuplicateHandle(GetCurrentProcess(), /* pseudo handle, don't close */ + request_queue.cond, /* handle to copy */ + GetCurrentProcess(), /* pseudo handle, don't close */ + &cond, + 0, /* required access */ + FALSE, /* child process's don't inherit the handle */ + DUPLICATE_SAME_ACCESS)) + exit(1); + if (!ReleaseMutex(request_queue.mutex)) { + CloseHandle(cond); + exit(1); + } + + + while (1) { + DWORD rv; + threadp->current_req = request = NULL; + request = NULL; + /* Get a request to process */ + threadp->status = _THREAD_WAITING; + rv = WaitForSingleObject( + request_queue.mutex, // handle to object + INFINITE // time-out interval + ); + if (rv == WAIT_FAILED) { + CloseHandle(cond); + return 1; + } + + + while (!request_queue.head) { + if (!ReleaseMutex(request_queue.mutex)) { + CloseHandle(cond); + threadp->status = _THREAD_FAILED; + return 1; + } + rv = WaitForSingleObject( + cond, // handle to object + INFINITE // time-out interval + ); + if (rv == WAIT_FAILED) { + CloseHandle(cond); + return 1; + } + rv = WaitForSingleObject( + request_queue.mutex, // handle to object + INFINITE // time-out interval + ); + if (rv == WAIT_FAILED) { + CloseHandle(cond); + return 1; + } + } + request = request_queue.head; + if (request) + request_queue.head = request->next; + if (!request_queue.head) + request_queue.tailp = &request_queue.head; + if (!ReleaseMutex(request_queue.mutex)) { + CloseHandle(cond); + return 1; + } + /* process the request */ + threadp->status = _THREAD_BUSY; + request->next = NULL; + threadp->current_req = request; + errno = 0; + if (!request->cancelled) { + switch (request->request_type) { + case _AIO_OP_OPEN: + squidaio_do_open(request); + break; + case _AIO_OP_READ: + squidaio_do_read(request); + break; + case _AIO_OP_WRITE: + squidaio_do_write(request); + break; + case _AIO_OP_CLOSE: + squidaio_do_close(request); + break; + case _AIO_OP_UNLINK: + squidaio_do_unlink(request); + break; + case _AIO_OP_TRUNCATE: + squidaio_do_truncate(request); + break; +#if AIO_OPENDIR /* Opendir not implemented yet */ + case _AIO_OP_OPENDIR: + squidaio_do_opendir(request); + break; +#endif + case _AIO_OP_STAT: + squidaio_do_stat(request); + break; + default: + request->ret = -1; + request->err = EINVAL; + break; + } + } else { /* cancelled */ + request->ret = -1; + request->err = EINTR; + } + threadp->status = _THREAD_DONE; + /* put the request in the done queue */ + rv = WaitForSingleObject( + done_queue.mutex, // handle to object + INFINITE // time-out interval + ); + if (rv == WAIT_FAILED) { + CloseHandle(cond); + return 1; + } + *done_queue.tailp = request; + done_queue.tailp = &request->next; + if (!ReleaseMutex(done_queue.mutex)) { + CloseHandle(cond); + return 1; + } + threadp->requests++; + } /* while forever */ + CloseHandle(cond); + return 0; +} /* squidaio_thread_loop */ + +static void +squidaio_queue_request(squidaio_request_t * request) +{ + static int high_start = 0; + debug(41, 9) ("squidaio_queue_request: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + /* Mark it as not executed (failing result, no error) */ + request->ret = -1; + request->err = 0; + /* Internal housekeeping */ + request_queue_len += 1; + request->resultp->_data = request; + /* Play some tricks with the request_queue2 queue */ + request->next = NULL; + if (!request_queue2.head) { + /* If queue2 is empty, insert into queue 1 and try to "push" the queue + If the "push" fails, queue it via queue2 */ + if (WaitForSingleObject(request_queue.mutex, 0)==WAIT_OBJECT_0) { + /* Normal path */ + *request_queue.tailp = request; + request_queue.tailp = &request->next; + if (!SetEvent(request_queue.cond)) + fatal("couldn't push queue\n"); + if (!ReleaseMutex(request_queue.mutex)) { + /* unexpected error */ + fatal("couldn't push queue\n"); + } + } else { + /* Oops, the request queue is blocked, use request_queue2 */ + *request_queue2.tailp = request; + request_queue2.tailp = &request->next; + } + } else { + /* Secondary path. We have blocked requests to deal with */ + /* add the request to the chain */ + *request_queue2.tailp = request; + if (WaitForSingleObject(request_queue.mutex, 0)==WAIT_OBJECT_0) { + /* Ok, the queue is no longer blocked */ + *request_queue.tailp = request_queue2.head; + request_queue.tailp = &request->next; + if (!SetEvent(request_queue.cond)) + fatal("couldn't push queue\n"); + if (!ReleaseMutex(request_queue.mutex)) { + /* unexpected error */ + fatal("couldn't push queue\n"); + } + request_queue2.head = NULL; + request_queue2.tailp = &request_queue2.head; + } else { + /* still blocked, bump the blocked request chain */ + request_queue2.tailp = &request->next; + } + } + if (request_queue2.head) { + static int filter = 0; + static int filter_limit = 8; + if (++filter >= filter_limit) { + filter_limit += filter; + filter = 0; + debug(43, 1) ("squidaio_queue_request: WARNING - Queue congestion\n"); + } + } + /* Warn if out of threads */ + if (request_queue_len > MAGIC1) { + static int last_warn = 0; + static int queue_high, queue_low; + if (high_start == 0) { + high_start = squid_curtime; + queue_high = request_queue_len; + queue_low = request_queue_len; + } + if (request_queue_len > queue_high) + queue_high = request_queue_len; + if (request_queue_len < queue_low) + queue_low = request_queue_len; + if (squid_curtime >= (last_warn + 15) && + squid_curtime >= (high_start + 5)) { + debug(43, 1) ("squidaio_queue_request: WARNING - Disk I/O overloading\n"); + if (squid_curtime >= (high_start + 15)) + debug(43, 1) ("squidaio_queue_request: Queue Length: current=%d, high=%d, low=%d, duration=%ld\n", + request_queue_len, queue_high, queue_low, (long int) (squid_curtime - high_start)); + last_warn = squid_curtime; + } + } else { + high_start = 0; + } + /* Warn if seriously overloaded */ + if (request_queue_len > RIDICULOUS_LENGTH) { + debug(43, 0) ("squidaio_queue_request: Async request queue growing uncontrollably!\n"); + debug(43, 0) ("squidaio_queue_request: Syncing pending I/O operations.. (blocking)\n"); + squidaio_sync(); + debug(43, 0) ("squidaio_queue_request: Synced\n"); + } +} /* squidaio_queue_request */ + +static void +squidaio_cleanup_request(squidaio_request_t * requestp) +{ + squidaio_result_t *resultp = requestp->resultp; + int cancelled = requestp->cancelled; + + /* Free allocated structures and copy data back to user space if the */ + /* request hasn't been cancelled */ + switch (requestp->request_type) { + case _AIO_OP_STAT: + if (!cancelled && requestp->ret == 0) + xmemcpy(requestp->statp, requestp->tmpstatp, sizeof(struct stat)); + squidaio_xfree(requestp->tmpstatp, sizeof(struct stat)); + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_OPEN: + if (cancelled && requestp->ret >= 0) + /* The open() was cancelled but completed */ + close(requestp->ret); + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_CLOSE: + if (cancelled && requestp->ret < 0) + /* The close() was cancelled and never got executed */ + close(requestp->fd); + break; + case _AIO_OP_UNLINK: + case _AIO_OP_TRUNCATE: + case _AIO_OP_OPENDIR: + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_READ: + if (!cancelled && requestp->ret > 0) + xmemcpy(requestp->bufferp, requestp->tmpbufp, requestp->ret); + squidaio_xfree(requestp->tmpbufp, requestp->buflen); + break; + case _AIO_OP_WRITE: + squidaio_xfree(requestp->tmpbufp, requestp->buflen); + break; + default: + break; + } + if (resultp != NULL && !cancelled) { + resultp->aio_return = requestp->ret; + resultp->aio_errno = requestp->err; + } + memPoolFree(squidaio_request_pool, requestp); +} /* squidaio_cleanup_request */ + + +int +squidaio_cancel(squidaio_result_t * resultp) +{ + squidaio_request_t *request = resultp->_data; + + if (request && request->resultp == resultp) { + debug(41, 9) ("squidaio_cancel: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + request->cancelled = 1; + request->resultp = NULL; + resultp->_data = NULL; + return 0; + } + return 1; +} /* squidaio_cancel */ + + +int +squidaio_open(const char *path, int oflag, mode_t mode, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->oflag = oflag; + requestp->mode = mode; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_OPEN; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_open(squidaio_request_t * requestp) +{ + requestp->ret = open(requestp->path, requestp->oflag, requestp->mode); + requestp->err = errno; +} + + +int +squidaio_read(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->bufferp = bufp; + requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); + requestp->buflen = bufs; + requestp->offset = offset; + requestp->whence = whence; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_READ; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_read(squidaio_request_t * requestp) +{ + lseek(requestp->fd, requestp->offset, requestp->whence); + requestp->ret = read(requestp->fd, requestp->tmpbufp, requestp->buflen); + requestp->err = errno; +} + + +int +squidaio_write(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); + xmemcpy(requestp->tmpbufp, bufp, bufs); + requestp->buflen = bufs; + requestp->offset = offset; + requestp->whence = whence; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_WRITE; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_write(squidaio_request_t * requestp) +{ + requestp->ret = write(requestp->fd, requestp->tmpbufp, requestp->buflen); + requestp->err = errno; +} + + +int +squidaio_close(int fd, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_CLOSE; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_close(squidaio_request_t * requestp) +{ + requestp->ret = close(requestp->fd); + requestp->err = errno; +} + + +int +squidaio_stat(const char *path, struct stat *sb, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->statp = sb; + requestp->tmpstatp = (struct stat *) squidaio_xmalloc(sizeof(struct stat)); + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_STAT; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_stat(squidaio_request_t * requestp) +{ + requestp->ret = stat(requestp->path, requestp->tmpstatp); + requestp->err = errno; +} + + +int +squidaio_unlink(const char *path, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->path = squidaio_xstrdup(path); + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_UNLINK; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_unlink(squidaio_request_t * requestp) +{ + requestp->ret = unlink(requestp->path); + requestp->err = errno; +} + +int +squidaio_truncate(const char *path, off_t length, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->offset = length; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_TRUNCATE; + requestp->cancelled = 0; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_truncate(squidaio_request_t * requestp) +{ + requestp->ret = truncate(requestp->path, requestp->offset); + requestp->err = errno; +} + + +#if AIO_OPENDIR +/* XXX squidaio_opendir NOT implemented yet.. */ + +int +squidaio_opendir(const char *path, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + int len; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + return -1; +} + +static void +squidaio_do_opendir(squidaio_request_t * requestp) +{ + /* NOT IMPLEMENTED */ +} + +#endif + +static void +squidaio_poll_queues(void) +{ + /* kick "overflow" request queue */ + if (request_queue2.head && + (WaitForSingleObject(request_queue.mutex, 0)==WAIT_OBJECT_0)) { + *request_queue.tailp = request_queue2.head; + request_queue.tailp = request_queue2.tailp; + if (!SetEvent(request_queue.cond)) + fatal("couldn't push queue\n"); + if (!ReleaseMutex(request_queue.mutex)) { + /* unexpected error */ + } + request_queue2.head = NULL; + request_queue2.tailp = &request_queue2.head; + } + /* poll done queue */ + if (done_queue.head && + (WaitForSingleObject(done_queue.mutex, 0)==WAIT_OBJECT_0)) { + struct squidaio_request_t *requests = done_queue.head; + done_queue.head = NULL; + done_queue.tailp = &done_queue.head; + if (!ReleaseMutex(done_queue.mutex)) { + /* unexpected error */ + } + *done_requests.tailp = requests; + request_queue_len -= 1; + while (requests->next) { + requests = requests->next; + request_queue_len -= 1; + } + done_requests.tailp = &requests->next; + } +} + +squidaio_result_t * +squidaio_poll_done(void) +{ + squidaio_request_t *request; + squidaio_result_t *resultp; + int cancelled; + int polled = 0; + + AIO_REPOLL: + request = done_requests.head; + if (request == NULL && !polled) { + squidaio_poll_queues(); + polled = 1; + request = done_requests.head; + } + if (!request) { + return NULL; + } + debug(41, 9) ("squidaio_poll_done: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + done_requests.head = request->next; + if (!done_requests.head) + done_requests.tailp = &done_requests.head; + resultp = request->resultp; + cancelled = request->cancelled; + squidaio_debug(request); + debug(43, 5) ("DONE: %d -> %d\n", request->ret, request->err); + squidaio_cleanup_request(request); + if (cancelled) + goto AIO_REPOLL; + return resultp; +} /* squidaio_poll_done */ + +int +squidaio_operations_pending(void) +{ + return request_queue_len + (done_requests.head ? 1 : 0); +} + +int +squidaio_sync(void) +{ + /* XXX This might take a while if the queue is large.. */ + do { + squidaio_poll_queues(); + } while (request_queue_len > 0); + return squidaio_operations_pending(); +} + +int +squidaio_get_queue_len(void) +{ + return request_queue_len; +} + +static void +squidaio_debug(squidaio_request_t * request) +{ + switch (request->request_type) { + case _AIO_OP_OPEN: + debug(43, 5) ("OPEN of %s to FD %d\n", request->path, request->ret); + break; + case _AIO_OP_READ: + debug(43, 5) ("READ on fd: %d\n", request->fd); + break; + case _AIO_OP_WRITE: + debug(43, 5) ("WRITE on fd: %d\n", request->fd); + break; + case _AIO_OP_CLOSE: + debug(43, 5) ("CLOSE of fd: %d\n", request->fd); + break; + case _AIO_OP_UNLINK: + debug(43, 5) ("UNLINK of %s\n", request->path); + break; + case _AIO_OP_TRUNCATE: + debug(43, 5) ("UNLINK of %s\n", request->path); + break; + default: + break; + } +} --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/async_io.c Wed Feb 14 00:57:26 2007 @@ -0,0 +1,360 @@ + +/* + * $Id: async_io.c,v 1.1.62.1 2002/03/14 20:23:47 serassio Exp $ + * + * DEBUG: section 32 Asynchronous Disk I/O + * AUTHOR: Pete Bentley + * AUTHOR: Stewart Forster + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "store_asyncufs.h" + +#define _AIO_OPEN 0 +#define _AIO_READ 1 +#define _AIO_WRITE 2 +#define _AIO_CLOSE 3 +#define _AIO_UNLINK 4 +#define _AIO_TRUNCATE 4 +#define _AIO_OPENDIR 5 +#define _AIO_STAT 6 + +typedef struct squidaio_ctrl_t { + struct squidaio_ctrl_t *next; + int fd; + int operation; + AIOCB *done_handler; + void *done_handler_data; + squidaio_result_t result; + char *bufp; + FREE *free_func; + dlink_node node; +} squidaio_ctrl_t; + +static struct { + int open; + int close; + int cancel; + int write; + int read; + int stat; + int unlink; + int check_callback; +} squidaio_counts; + +typedef struct squidaio_unlinkq_t { + char *path; + struct squidaio_unlinkq_t *next; +} squidaio_unlinkq_t; + +static dlink_list used_list; +static int initialised = 0; +static OBJH aioStats; +static MemPool *squidaio_ctrl_pool; +static void aioFDWasClosed(int fd); + +static void +aioFDWasClosed(int fd) +{ + if (fd_table[fd].flags.closing) + fd_close(fd); +} + +void +aioInit(void) +{ + if (initialised) + return; + squidaio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(squidaio_ctrl_t)); + cachemgrRegister("squidaio_counts", "Async IO Function Counters", + aioStats, 0, 1); + initialised = 1; + comm_quick_poll_required(); +} + +void +aioDone(void) +{ + memPoolDestroy(squidaio_ctrl_pool); + initialised = 0; +} + +void +aioOpen(const char *path, int oflag, mode_t mode, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.open++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_OPEN; + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_open(path, oflag, mode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} + +void +aioClose(int fd) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.close++; + aioCancel(fd); + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = NULL; + ctrlp->done_handler_data = NULL; + ctrlp->operation = _AIO_CLOSE; + ctrlp->result.data = ctrlp; + squidaio_close(fd, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} + +void +aioCancel(int fd) +{ + squidaio_ctrl_t *curr; + AIOCB *done_handler; + void *their_data; + dlink_node *m, *next; + + assert(initialised); + squidaio_counts.cancel++; + for (m = used_list.head; m; m = next) { + next = m->next; + curr = m->data; + if (curr->fd != fd) + continue; + + squidaio_cancel(&curr->result); + + if ((done_handler = curr->done_handler)) { + their_data = curr->done_handler_data; + curr->done_handler = NULL; + curr->done_handler_data = NULL; + debug(32, 2) ("this be aioCancel\n"); + if (cbdataValid(their_data)) + done_handler(fd, their_data, -2, -2); + cbdataUnlock(their_data); + } + dlinkDelete(m, &used_list); + memPoolFree(squidaio_ctrl_pool, curr); + } +} + + +void +aioWrite(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data, FREE * free_func) +{ + squidaio_ctrl_t *ctrlp; + int seekmode; + + assert(initialised); + squidaio_counts.write++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_WRITE; + ctrlp->bufp = bufp; + ctrlp->free_func = free_func; + if (offset >= 0) + seekmode = SEEK_SET; + else { + seekmode = SEEK_END; + offset = 0; + } + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_write(fd, bufp, len, offset, seekmode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioWrite */ + + +void +aioRead(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + int seekmode; + + assert(initialised); + squidaio_counts.read++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_READ; + if (offset >= 0) + seekmode = SEEK_SET; + else { + seekmode = SEEK_CUR; + offset = 0; + } + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_read(fd, bufp, len, offset, seekmode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} /* aioRead */ + +void +aioStat(char *path, struct stat *sb, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.stat++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_STAT; + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_stat(path, sb, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} /* aioStat */ + +void +aioUnlink(const char *path, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + assert(initialised); + squidaio_counts.unlink++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_UNLINK; + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_unlink(path, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioUnlink */ + +void +aioTruncate(const char *path, off_t length, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + assert(initialised); + squidaio_counts.unlink++; + ctrlp = memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = callback_data; + ctrlp->operation = _AIO_TRUNCATE; + cbdataLock(callback_data); + ctrlp->result.data = ctrlp; + squidaio_truncate(path, length, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioTruncate */ + + +int +aioCheckCallbacks(SwapDir * SD) +{ + squidaio_result_t *resultp; + squidaio_ctrl_t *ctrlp; + AIOCB *done_handler; + void *their_data; + int retval = 0; + + assert(initialised); + squidaio_counts.check_callback++; + for (;;) { + if ((resultp = squidaio_poll_done()) == NULL) + break; + ctrlp = (squidaio_ctrl_t *) resultp->data; + if (ctrlp == NULL) + continue; /* XXX Should not happen */ + dlinkDelete(&ctrlp->node, &used_list); + if ((done_handler = ctrlp->done_handler)) { + their_data = ctrlp->done_handler_data; + ctrlp->done_handler = NULL; + ctrlp->done_handler_data = NULL; + if (cbdataValid(their_data)) { + retval = 1; /* Return that we've actually done some work */ + done_handler(ctrlp->fd, their_data, + ctrlp->result.aio_return, ctrlp->result.aio_errno); + } + cbdataUnlock(their_data); + } + /* free data if requested to aioWrite() */ + if (ctrlp->free_func) + ctrlp->free_func(ctrlp->bufp); + if (ctrlp->operation == _AIO_CLOSE) + aioFDWasClosed(ctrlp->fd); + memPoolFree(squidaio_ctrl_pool, ctrlp); + } + return retval; +} + +void +aioStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "ASYNC IO Counters:\n"); + storeAppendPrintf(sentry, "open\t%d\n", squidaio_counts.open); + storeAppendPrintf(sentry, "close\t%d\n", squidaio_counts.close); + storeAppendPrintf(sentry, "cancel\t%d\n", squidaio_counts.cancel); + storeAppendPrintf(sentry, "write\t%d\n", squidaio_counts.write); + storeAppendPrintf(sentry, "read\t%d\n", squidaio_counts.read); + storeAppendPrintf(sentry, "stat\t%d\n", squidaio_counts.stat); + storeAppendPrintf(sentry, "unlink\t%d\n", squidaio_counts.unlink); + storeAppendPrintf(sentry, "check_callback\t%d\n", squidaio_counts.check_callback); + storeAppendPrintf(sentry, "queue\t%d\n", squidaio_get_queue_len()); +} + +/* Flush all pending I/O */ +void +aioSync(SwapDir * SD) +{ + if (!initialised) + return; /* nothing to do then */ + /* Flush all pending operations */ + debug(32, 1) ("aioSync: flushing pending I/O operations\n"); + do { + aioCheckCallbacks(SD); + } while (squidaio_sync()); + debug(32, 1) ("aioSync: done\n"); +} + +int +aioQueueSize(void) +{ + return memPoolInUseCount(squidaio_ctrl_pool); +} --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/store_asyncufs.h Wed Feb 14 00:57:27 2007 @@ -0,0 +1,132 @@ +/* + * store_aufs.h + * + * Internal declarations for the aufs routines + */ + +#ifndef __STORE_ASYNCUFS_H__ +#define __STORE_ASYNCUFS_H__ + +#ifdef AUFS_IO_THREADS +#define NUMTHREADS AUFS_IO_THREADS +#else +#define NUMTHREADS (Config.cacheSwap.n_configured*16) +#endif + +/* Queue limit where swapouts are deferred (load calculation) */ +#define MAGIC1 (NUMTHREADS*Config.cacheSwap.n_configured*5) +/* Queue limit where swapins are deferred (open/create fails) */ +#define MAGIC2 (NUMTHREADS*Config.cacheSwap.n_configured*20) + +/* Which operations to run async */ +#define ASYNC_OPEN 1 +#define ASYNC_CLOSE 0 +#define ASYNC_CREATE 1 +#define ASYNC_WRITE 0 +#define ASYNC_READ 1 + +struct _squidaio_result_t { + int aio_return; + int aio_errno; + void *_data; /* Internal housekeeping */ + void *data; /* Available to the caller */ +}; + +typedef struct _squidaio_result_t squidaio_result_t; + +typedef void AIOCB(int fd, void *, int aio_return, int aio_errno); + +int squidaio_cancel(squidaio_result_t *); +int squidaio_open(const char *, int, mode_t, squidaio_result_t *); +int squidaio_read(int, char *, int, off_t, int, squidaio_result_t *); +int squidaio_write(int, char *, int, off_t, int, squidaio_result_t *); +int squidaio_close(int, squidaio_result_t *); +int squidaio_stat(const char *, struct stat *, squidaio_result_t *); +int squidaio_unlink(const char *, squidaio_result_t *); +int squidaio_truncate(const char *, off_t length, squidaio_result_t *); +int squidaio_opendir(const char *, squidaio_result_t *); +squidaio_result_t *squidaio_poll_done(void); +int squidaio_operations_pending(void); +int squidaio_sync(void); +int squidaio_get_queue_len(void); + +void aioInit(void); +void aioDone(void); +void aioCancel(int); +void aioOpen(const char *, int, mode_t, AIOCB *, void *); +void aioClose(int); +void aioWrite(int, int offset, char *, int size, AIOCB *, void *, FREE *); +void aioRead(int, int offset, char *, int size, AIOCB *, void *); +void aioStat(char *, struct stat *, AIOCB *, void *); +void aioUnlink(const char *, AIOCB *, void *); +void aioTruncate(const char *, off_t length, AIOCB *, void *); +int aioCheckCallbacks(SwapDir *); +void aioSync(SwapDir *); +int aioQueueSize(void); + +struct _squidaioinfo_t { + int swaplog_fd; + int l1; + int l2; + fileMap *map; + int suggest; +}; + +struct _squidaiostate_t { + int fd; + struct { + unsigned int close_request:1; + unsigned int reading:1; + unsigned int writing:1; + unsigned int opening:1; + unsigned int write_kicking:1; + unsigned int read_kicking:1; + unsigned int inreaddone:1; + } flags; + const char *read_buf; + link_list *pending_writes; + link_list *pending_reads; +}; + +struct _queued_write { + char *buf; + size_t size; + off_t offset; + FREE *free_func; +}; + +struct _queued_read { + char *buf; + size_t size; + off_t offset; + STRCB *callback; + void *callback_data; +}; + +typedef struct _squidaioinfo_t squidaioinfo_t; +typedef struct _squidaiostate_t squidaiostate_t; + +/* The squidaio_state memory pools */ +extern MemPool *squidaio_state_pool; +extern MemPool *aufs_qread_pool; +extern MemPool *aufs_qwrite_pool; + +extern void storeAufsDirMapBitReset(SwapDir *, sfileno); +extern int storeAufsDirMapBitAllocate(SwapDir *); + +extern char *storeAufsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath); +extern void storeAufsDirUnlinkFile(SwapDir *, sfileno); +extern void storeAufsDirReplAdd(SwapDir * SD, StoreEntry *); +extern void storeAufsDirReplRemove(StoreEntry *); + +/* + * Store IO stuff + */ +extern STOBJCREATE storeAufsCreate; +extern STOBJOPEN storeAufsOpen; +extern STOBJCLOSE storeAufsClose; +extern STOBJREAD storeAufsRead; +extern STOBJWRITE storeAufsWrite; +extern STOBJUNLINK storeAufsUnlink; + +#endif --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/store_dir_aufs.c Wed Feb 14 00:57:27 2007 @@ -0,0 +1,1712 @@ + +/* + * $Id: store_dir_aufs.c,v 1.1.62.1 2002/03/14 20:23:47 serassio Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +#include "store_asyncufs.h" + +#define DefaultLevelOneDirs 16 +#define DefaultLevelTwoDirs 256 +#define STORE_META_BUFSZ 4096 + +typedef struct _RebuildState RebuildState; +struct _RebuildState { + SwapDir *sd; + int n_read; + FILE *log; + int speed; + int curlvl1; + int curlvl2; + struct { + unsigned int need_to_validate:1; + unsigned int clean:1; + unsigned int init:1; + } flags; + int done; + int in_dir; + int fn; + struct dirent *entry; + DIR *td; + char fullpath[SQUID_MAXPATHLEN]; + char fullfilename[SQUID_MAXPATHLEN]; + struct _store_rebuild_data counts; +}; + +static int n_asyncufs_dirs = 0; +static int *asyncufs_dir_index = NULL; +MemPool *squidaio_state_pool = NULL; +MemPool *aufs_qread_pool = NULL; +MemPool *aufs_qwrite_pool = NULL; +static int asyncufs_initialised = 0; + +static char *storeAufsDirSwapSubDir(SwapDir *, int subdirn); +static int storeAufsDirCreateDirectory(const char *path, int); +static int storeAufsDirVerifyCacheDirs(SwapDir *); +static int storeAufsDirVerifyDirectory(const char *path); +static void storeAufsDirCreateSwapSubDirs(SwapDir *); +static char *storeAufsDirSwapLogFile(SwapDir *, const char *); +static EVH storeAufsDirRebuildFromDirectory; +static EVH storeAufsDirRebuildFromSwapLog; +static int storeAufsDirGetNextFile(RebuildState *, sfileno *, int *size); +static StoreEntry *storeAufsDirAddDiskRestore(SwapDir * SD, const cache_key * key, + sfileno file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_num32 refcount, + u_short flags, + int clean); +static void storeAufsDirRebuild(SwapDir * sd); +static void storeAufsDirCloseTmpSwapLog(SwapDir * sd); +static FILE *storeAufsDirOpenTmpSwapLog(SwapDir *, int *, int *); +static STLOGOPEN storeAufsDirOpenSwapLog; +static STINIT storeAufsDirInit; +static STFREE storeAufsDirFree; +static STLOGCLEANSTART storeAufsDirWriteCleanStart; +static STLOGCLEANNEXTENTRY storeAufsDirCleanLogNextEntry; +static STLOGCLEANWRITE storeAufsDirWriteCleanEntry; +static STLOGCLEANDONE storeAufsDirWriteCleanDone; +static STLOGCLOSE storeAufsDirCloseSwapLog; +static STLOGWRITE storeAufsDirSwapLog; +static STNEWFS storeAufsDirNewfs; +static STDUMP storeAufsDirDump; +static STMAINTAINFS storeAufsDirMaintain; +static STCHECKOBJ storeAufsDirCheckObj; +static STREFOBJ storeAufsDirRefObj; +static STUNREFOBJ storeAufsDirUnrefObj; +static QS rev_int_sort; +static int storeAufsDirClean(int swap_index); +static EVH storeAufsDirCleanEvent; +static int storeAufsDirIs(SwapDir * sd); +static int storeAufsFilenoBelongsHere(int fn, int F0, int F1, int F2); +static int storeAufsCleanupDoubleCheck(SwapDir *, StoreEntry *); +static void storeAufsDirStats(SwapDir *, StoreEntry *); +static void storeAufsDirInitBitmap(SwapDir *); +static int storeAufsDirValidFileno(SwapDir *, sfileno, int); + +/* The MAIN externally visible function */ +STSETUP storeFsSetup_awin32; + +/* + * These functions were ripped straight out of the heart of store_dir.c. + * They assume that the given filenum is on a asyncufs partiton, which may or + * may not be true.. + * XXX this evilness should be tidied up at a later date! + */ + +static int +storeAufsDirMapBitTest(SwapDir * SD, sfileno filn) +{ + squidaioinfo_t *aioinfo; + aioinfo = (squidaioinfo_t *) SD->fsdata; + return file_map_bit_test(aioinfo->map, filn); +} + +static void +storeAufsDirMapBitSet(SwapDir * SD, sfileno filn) +{ + squidaioinfo_t *aioinfo; + aioinfo = (squidaioinfo_t *) SD->fsdata; + file_map_bit_set(aioinfo->map, filn); +} + +void +storeAufsDirMapBitReset(SwapDir * SD, sfileno filn) +{ + squidaioinfo_t *aioinfo; + aioinfo = (squidaioinfo_t *) SD->fsdata; + /* + * We have to test the bit before calling file_map_bit_reset. + * file_map_bit_reset doesn't do bounds checking. It assumes + * filn is a valid file number, but it might not be because + * the map is dynamic in size. Also clearing an already clear + * bit puts the map counter of-of-whack. + */ + if (file_map_bit_test(aioinfo->map, filn)) + file_map_bit_reset(aioinfo->map, filn); +} + +int +storeAufsDirMapBitAllocate(SwapDir * SD) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) SD->fsdata; + int fn; + fn = file_map_allocate(aioinfo->map, aioinfo->suggest); + file_map_bit_set(aioinfo->map, fn); + aioinfo->suggest = fn + 1; + return fn; +} + +/* + * Initialise the asyncufs bitmap + * + * If there already is a bitmap, and the numobjects is larger than currently + * configured, we allocate a new bitmap and 'grow' the old one into it. + */ +static void +storeAufsDirInitBitmap(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + + if (aioinfo->map == NULL) { + /* First time */ + aioinfo->map = file_map_create(); + } else if (aioinfo->map->max_n_files) { + /* it grew, need to expand */ + /* XXX We don't need it anymore .. */ + } + /* else it shrunk, and we leave the old one in place */ +} + +static char * +storeAufsDirSwapSubDir(SwapDir * sd, int subdirn) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + + LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); + assert(0 <= subdirn && subdirn < aioinfo->l1); + snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", sd->path, subdirn); + return fullfilename; +} + +static int +storeAufsDirCreateDirectory(const char *path, int should_exist) +{ + int created = 0; + struct stat st; + getCurrentTime(); + if (0 == stat(path, &st)) { + if (S_ISDIR(st.st_mode)) { + debug(20, should_exist ? 3 : 1) ("%s exists\n", path); + } else { + fatalf("Swap directory %s is not a directory.", path); + } + } else if (0 == mkdir(path, 0755)) { + debug(20, should_exist ? 1 : 3) ("%s created\n", path); + created = 1; + } else { + fatalf("Failed to make swap directory %s: %s", + path, xstrerror()); + } + return created; +} + +static int +storeAufsDirVerifyDirectory(const char *path) +{ + struct stat sb; + if (stat(path, &sb) < 0) { + debug(20, 0) ("%s: %s\n", path, xstrerror()); + return -1; + } + if (S_ISDIR(sb.st_mode) == 0) { + debug(20, 0) ("%s is not a directory\n", path); + return -1; + } + return 0; +} + +/* + * This function is called by storeAufsDirInit(). If this returns < 0, + * then Squid exits, complains about swap directories not + * existing, and instructs the admin to run 'squid -z' + */ +static int +storeAufsDirVerifyCacheDirs(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + int j; + const char *path = sd->path; + + if (storeAufsDirVerifyDirectory(path) < 0) + return -1; + for (j = 0; j < aioinfo->l1; j++) { + path = storeAufsDirSwapSubDir(sd, j); + if (storeAufsDirVerifyDirectory(path) < 0) + return -1; + } + return 0; +} + +static void +storeAufsDirCreateSwapSubDirs(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + int i, k; + int should_exist; + LOCAL_ARRAY(char, name, MAXPATHLEN); + for (i = 0; i < aioinfo->l1; i++) { + snprintf(name, MAXPATHLEN, "%s/%02X", sd->path, i); + if (storeAufsDirCreateDirectory(name, 0)) + should_exist = 0; + else + should_exist = 1; + debug(47, 1) ("Making directories in %s\n", name); + for (k = 0; k < aioinfo->l2; k++) { + snprintf(name, MAXPATHLEN, "%s/%02X/%02X", sd->path, i, k); + storeAufsDirCreateDirectory(name, should_exist); + } + } +} + +static char * +storeAufsDirSwapLogFile(SwapDir * sd, const char *ext) +{ + LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, digit, 32); + char *pathtmp2; + if (Config.Log.swap) { + xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); + pathtmp2 = pathtmp; + while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL) + *pathtmp2 = '.'; + while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.') + pathtmp[strlen(pathtmp) - 1] = '\0'; + for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); + snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2); + if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { + strcat(path, "."); + snprintf(digit, 32, "%02d", sd->index); + strncat(path, digit, 3); + } + } else { + xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); + strcat(path, "/swap.state"); + } + if (ext) + strncat(path, ext, 16); + return path; +} + +static void +storeAufsDirOpenSwapLog(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + char *path; + int fd; + path = storeAufsDirSwapLogFile(sd, NULL); + fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + fatal("storeAufsDirOpenSwapLog: Failed to open swap log."); + } + debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); + aioinfo->swaplog_fd = fd; + if (0 == n_asyncufs_dirs) + assert(NULL == asyncufs_dir_index); + n_asyncufs_dirs++; + assert(n_asyncufs_dirs <= Config.cacheSwap.n_configured); +} + +static void +storeAufsDirCloseSwapLog(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + if (aioinfo->swaplog_fd < 0) /* not open */ + return; + file_close(aioinfo->swaplog_fd); + debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", + sd->index, aioinfo->swaplog_fd); + aioinfo->swaplog_fd = -1; + n_asyncufs_dirs--; + assert(n_asyncufs_dirs >= 0); + if (0 == n_asyncufs_dirs) + safe_free(asyncufs_dir_index); +} + +static void +storeAufsDirInit(SwapDir * sd) +{ + static int started_clean_event = 0; + static const char *errmsg = + "\tFailed to verify one of the swap directories, Check cache.log\n" + "\tfor details. Run 'squid -z' to create swap directories\n" + "\tif needed, or if running Squid for the first time."; + storeAufsDirInitBitmap(sd); + if (storeAufsDirVerifyCacheDirs(sd) < 0) + fatal(errmsg); + storeAufsDirOpenSwapLog(sd); + storeAufsDirRebuild(sd); + if (!started_clean_event) { + eventAdd("storeDirClean", storeAufsDirCleanEvent, NULL, 15.0, 1); + started_clean_event = 1; + } + (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize); +} + +static void +storeAufsDirRebuildFromDirectory(void *data) +{ + RebuildState *rb = data; + SwapDir *SD = rb->sd; + LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE); + StoreEntry *e = NULL; + StoreEntry tmpe; + cache_key key[MD5_DIGEST_CHARS]; + sfileno filn = 0; + int count; + int size; + struct stat sb; + int swap_hdr_len; + int fd = -1; + tlv *tlv_list; + tlv *t; + assert(rb != NULL); + debug(20, 3) ("storeAufsDirRebuildFromDirectory: DIR #%d\n", rb->sd->index); + for (count = 0; count < rb->speed; count++) { + assert(fd == -1); + fd = storeAufsDirGetNextFile(rb, &filn, &size); + if (fd == -2) { + debug(20, 1) ("Done scanning %s swaplog (%d entries)\n", + rb->sd->path, rb->n_read); + store_dirs_rebuilding--; + storeAufsDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); + return; + } else if (fd < 0) { + continue; + } + assert(fd > -1); + /* lets get file stats here */ + if (fstat(fd, &sb) < 0) { + debug(20, 1) ("storeAufsDirRebuildFromDirectory: fstat(FD %d): %s\n", + fd, xstrerror()); + file_close(fd); + store_open_disk_fd--; + fd = -1; + continue; + } + if ((++rb->counts.scancount & 0xFFFF) == 0) + debug(20, 3) (" %s %7d files opened so far.\n", + rb->sd->path, rb->counts.scancount); + debug(20, 9) ("file_in: fd=%d %08X\n", fd, filn); + statCounter.syscalls.disk.reads++; + if (read(fd, hdr_buf, SM_PAGE_SIZE) < 0) { + debug(20, 1) ("storeAufsDirRebuildFromDirectory: read(FD %d): %s\n", + fd, xstrerror()); + file_close(fd); + store_open_disk_fd--; + fd = -1; + continue; + } + file_close(fd); + store_open_disk_fd--; + fd = -1; + swap_hdr_len = 0; +#if USE_TRUNCATE + if (sb.st_size == 0) + continue; +#endif + tlv_list = storeSwapMetaUnpack(hdr_buf, &swap_hdr_len); + if (tlv_list == NULL) { + debug(20, 1) ("storeAufsDirRebuildFromDirectory: failed to get meta data\n"); + /* XXX shouldn't this be a call to storeAufsUnlink ? */ + storeAufsDirUnlinkFile(SD, filn); + continue; + } + debug(20, 3) ("storeAufsDirRebuildFromDirectory: successful swap meta unpacking\n"); + memset(key, '\0', MD5_DIGEST_CHARS); + memset(&tmpe, '\0', sizeof(StoreEntry)); + for (t = tlv_list; t; t = t->next) { + switch (t->type) { + case STORE_META_KEY: + assert(t->length == MD5_DIGEST_CHARS); + xmemcpy(key, t->value, MD5_DIGEST_CHARS); + break; + case STORE_META_STD: + assert(t->length == STORE_HDR_METASIZE); + xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE); + break; + default: + break; + } + } + storeSwapTLVFree(tlv_list); + tlv_list = NULL; + if (storeKeyNull(key)) { + debug(20, 1) ("storeAufsDirRebuildFromDirectory: NULL key\n"); + storeAufsDirUnlinkFile(SD, filn); + continue; + } + tmpe.hash.key = key; + /* check sizes */ + if (tmpe.swap_file_sz == 0) { + tmpe.swap_file_sz = sb.st_size; + } else if (tmpe.swap_file_sz == sb.st_size - swap_hdr_len) { + tmpe.swap_file_sz = sb.st_size; + } else if (tmpe.swap_file_sz != sb.st_size) { + debug(20, 1) ("storeAufsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n", + (long int) tmpe.swap_file_sz, (long int) sb.st_size); + storeAufsDirUnlinkFile(SD, filn); + continue; + } + if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { + storeAufsDirUnlinkFile(SD, filn); + rb->counts.badflags++; + continue; + } + e = storeGet(key); + if (e && e->lastref >= tmpe.lastref) { + /* key already exists, current entry is newer */ + /* keep old, ignore new */ + rb->counts.dupcount++; + continue; + } else if (NULL != e) { + /* URL already exists, this swapfile not being used */ + /* junk old, load new */ + storeRelease(e); /* release old entry */ + rb->counts.dupcount++; + } + rb->counts.objcount++; + storeEntryDump(&tmpe, 5); + e = storeAufsDirAddDiskRestore(SD, key, + filn, + tmpe.swap_file_sz, + tmpe.expires, + tmpe.timestamp, + tmpe.lastref, + tmpe.lastmod, + tmpe.refcount, /* refcount */ + tmpe.flags, /* flags */ + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); + } + eventAdd("storeRebuild", storeAufsDirRebuildFromDirectory, rb, 0.0, 1); +} + +static void +storeAufsDirRebuildFromSwapLog(void *data) +{ + RebuildState *rb = data; + SwapDir *SD = rb->sd; + StoreEntry *e = NULL; + storeSwapLogData s; + size_t ss = sizeof(storeSwapLogData); + int count; + int used; /* is swapfile already in use? */ + int disk_entry_newer; /* is the log entry newer than current entry? */ + double x; + assert(rb != NULL); + /* load a number of objects per invocation */ + for (count = 0; count < rb->speed; count++) { + if (fread(&s, ss, 1, rb->log) != 1) { + debug(20, 1) ("Done reading %s swaplog (%d entries)\n", + rb->sd->path, rb->n_read); + fclose(rb->log); + rb->log = NULL; + store_dirs_rebuilding--; + storeAufsDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); + return; + } + rb->n_read++; + if (s.op <= SWAP_LOG_NOP) + continue; + if (s.op >= SWAP_LOG_MAX) + continue; + /* + * BC: during 2.4 development, we changed the way swap file + * numbers are assigned and stored. The high 16 bits used + * to encode the SD index number. There used to be a call + * to storeDirProperFileno here that re-assigned the index + * bits. Now, for backwards compatibility, we just need + * to mask it off. + */ + s.swap_filen &= 0x00FFFFFF; + debug(20, 3) ("storeAufsDirRebuildFromSwapLog: %s %s %08X\n", + swap_log_op_str[(int) s.op], + storeKeyText(s.key), + s.swap_filen); + if (s.op == SWAP_LOG_ADD) { + (void) 0; + } else if (s.op == SWAP_LOG_DEL) { + if ((e = storeGet(s.key)) != NULL) { + /* + * Make sure we don't unlink the file, it might be + * in use by a subsequent entry. Also note that + * we don't have to subtract from store_swap_size + * because adding to store_swap_size happens in + * the cleanup procedure. + */ + storeExpireNow(e); + storeReleaseRequest(e); + if (e->swap_filen > -1) { + storeAufsDirReplRemove(e); + storeAufsDirMapBitReset(SD, e->swap_filen); + e->swap_filen = -1; + e->swap_dirn = -1; + } + storeRelease(e); + rb->counts.objcount--; + rb->counts.cancelcount++; + } + continue; + } else { + x = log(++rb->counts.bad_log_op) / log(10.0); + if (0.0 == x - (double) (int) x) + debug(20, 1) ("WARNING: %d invalid swap log entries found\n", + rb->counts.bad_log_op); + rb->counts.invalid++; + continue; + } + if ((++rb->counts.scancount & 0xFFF) == 0) { + struct stat sb; + if (0 == fstat(fileno(rb->log), &sb)) + storeRebuildProgress(SD->index, + (int) sb.st_size / ss, rb->n_read); + } + if (!storeAufsDirValidFileno(SD, s.swap_filen, 0)) { + rb->counts.invalid++; + continue; + } + if (EBIT_TEST(s.flags, KEY_PRIVATE)) { + rb->counts.badflags++; + continue; + } + e = storeGet(s.key); + used = storeAufsDirMapBitTest(SD, s.swap_filen); + /* If this URL already exists in the cache, does the swap log + * appear to have a newer entry? Compare 'lastref' from the + * swap log to e->lastref. */ + disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; + if (used && !disk_entry_newer) { + /* log entry is old, ignore it */ + rb->counts.clashcount++; + continue; + } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == SD->index) { + /* swapfile taken, same URL, newer, update meta */ + if (e->store_status == STORE_OK) { + e->lastref = s.timestamp; + e->timestamp = s.timestamp; + e->expires = s.expires; + e->lastmod = s.lastmod; + e->flags = s.flags; + e->refcount += s.refcount; + storeAufsDirUnrefObj(SD, e); + } else { + debug_trap("storeAufsDirRebuildFromSwapLog: bad condition"); + debug(20, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); + } + continue; + } else if (used) { + /* swapfile in use, not by this URL, log entry is newer */ + /* This is sorta bad: the log entry should NOT be newer at this + * point. If the log is dirty, the filesize check should have + * caught this. If the log is clean, there should never be a + * newer entry. */ + debug(20, 1) ("WARNING: newer swaplog entry for dirno %d, fileno %08X\n", + SD->index, s.swap_filen); + /* I'm tempted to remove the swapfile here just to be safe, + * but there is a bad race condition in the NOVM version if + * the swapfile has recently been opened for writing, but + * not yet opened for reading. Because we can't map + * swapfiles back to StoreEntrys, we don't know the state + * of the entry using that file. */ + /* We'll assume the existing entry is valid, probably because + * were in a slow rebuild and the the swap file number got taken + * and the validation procedure hasn't run. */ + assert(rb->flags.need_to_validate); + rb->counts.clashcount++; + continue; + } else if (e && !disk_entry_newer) { + /* key already exists, current entry is newer */ + /* keep old, ignore new */ + rb->counts.dupcount++; + continue; + } else if (e) { + /* key already exists, this swapfile not being used */ + /* junk old, load new */ + storeExpireNow(e); + storeReleaseRequest(e); + if (e->swap_filen > -1) { + storeAufsDirReplRemove(e); + /* Make sure we don't actually unlink the file */ + storeAufsDirMapBitReset(SD, e->swap_filen); + e->swap_filen = -1; + e->swap_dirn = -1; + } + storeRelease(e); + rb->counts.dupcount++; + } else { + /* URL doesnt exist, swapfile not in use */ + /* load new */ + (void) 0; + } + /* update store_swap_size */ + rb->counts.objcount++; + e = storeAufsDirAddDiskRestore(SD, s.key, + s.swap_filen, + s.swap_file_sz, + s.expires, + s.timestamp, + s.lastref, + s.lastmod, + s.refcount, + s.flags, + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); + } + eventAdd("storeRebuild", storeAufsDirRebuildFromSwapLog, rb, 0.0, 1); +} + +static int +storeAufsDirGetNextFile(RebuildState * rb, sfileno * filn_p, int *size) +{ + SwapDir *SD = rb->sd; + squidaioinfo_t *aioinfo = (squidaioinfo_t *) SD->fsdata; + int fd = -1; + int used = 0; + int dirs_opened = 0; + debug(20, 3) ("storeAufsDirGetNextFile: flag=%d, %d: /%02X/%02X\n", + rb->flags.init, + rb->sd->index, + rb->curlvl1, + rb->curlvl2); + if (rb->done) + return -2; + while (fd < 0 && rb->done == 0) { + fd = -1; + if (0 == rb->flags.init) { /* initialize, open first file */ + rb->done = 0; + rb->curlvl1 = 0; + rb->curlvl2 = 0; + rb->in_dir = 0; + rb->flags.init = 1; + assert(Config.cacheSwap.n_configured > 0); + } + if (0 == rb->in_dir) { /* we need to read in a new directory */ + snprintf(rb->fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X", + rb->sd->path, + rb->curlvl1, rb->curlvl2); + if (rb->flags.init && rb->td != NULL) + closedir(rb->td); + rb->td = NULL; + if (dirs_opened) + return -1; + rb->td = opendir(rb->fullpath); + dirs_opened++; + if (rb->td == NULL) { + debug(50, 1) ("storeAufsDirGetNextFile: opendir: %s: %s\n", + rb->fullpath, xstrerror()); + } else { + rb->entry = readdir(rb->td); /* skip . and .. */ + rb->entry = readdir(rb->td); + if (rb->entry == NULL && errno == ENOENT) + debug(20, 1) ("storeAufsDirGetNextFile: directory does not exist!.\n"); + debug(20, 3) ("storeAufsDirGetNextFile: Directory %s\n", rb->fullpath); + } + } + if (rb->td != NULL && (rb->entry = readdir(rb->td)) != NULL) { + rb->in_dir++; + if (sscanf(rb->entry->d_name, "%x", &rb->fn) != 1) { + debug(20, 3) ("storeAufsDirGetNextFile: invalid %s\n", + rb->entry->d_name); + continue; + } + if (!storeAufsFilenoBelongsHere(rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2)) { + debug(20, 3) ("storeAufsDirGetNextFile: %08X does not belong in %d/%d/%d\n", + rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2); + continue; + } + used = storeAufsDirMapBitTest(SD, rb->fn); + if (used) { + debug(20, 3) ("storeAufsDirGetNextFile: Locked, continuing with next.\n"); + continue; + } + snprintf(rb->fullfilename, SQUID_MAXPATHLEN, "%s/%s", + rb->fullpath, rb->entry->d_name); + debug(20, 3) ("storeAufsDirGetNextFile: Opening %s\n", rb->fullfilename); + fd = file_open(rb->fullfilename, O_RDONLY | O_BINARY); + if (fd < 0) + debug(50, 1) ("storeAufsDirGetNextFile: %s: %s\n", rb->fullfilename, xstrerror()); + else + store_open_disk_fd++; + continue; + } + rb->in_dir = 0; + if (++rb->curlvl2 < aioinfo->l2) + continue; + rb->curlvl2 = 0; + if (++rb->curlvl1 < aioinfo->l1) + continue; + rb->curlvl1 = 0; + rb->done = 1; + } + *filn_p = rb->fn; + return fd; +} + +/* Add a new object to the cache with empty memory copy and pointer to disk + * use to rebuild store from disk. */ +static StoreEntry * +storeAufsDirAddDiskRestore(SwapDir * SD, const cache_key * key, + sfileno file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_num32 refcount, + u_short flags, + int clean) +{ + StoreEntry *e = NULL; + debug(20, 5) ("storeAufsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); + /* if you call this you'd better be sure file_number is not + * already in use! */ + e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); + e->store_status = STORE_OK; + storeSetMemStatus(e, NOT_IN_MEMORY); + e->swap_status = SWAPOUT_DONE; + e->swap_filen = file_number; + e->swap_dirn = SD->index; + e->swap_file_sz = swap_file_sz; + e->lock_count = 0; + e->lastref = lastref; + e->timestamp = timestamp; + e->expires = expires; + e->lastmod = lastmod; + e->refcount = refcount; + e->flags = flags; + EBIT_SET(e->flags, ENTRY_CACHABLE); + EBIT_CLR(e->flags, RELEASE_REQUEST); + EBIT_CLR(e->flags, KEY_PRIVATE); + e->ping_status = PING_NONE; + EBIT_CLR(e->flags, ENTRY_VALIDATED); + storeAufsDirMapBitSet(SD, e->swap_filen); + storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ + storeAufsDirReplAdd(SD, e); + return e; +} + +CBDATA_TYPE(RebuildState); + +static void +storeAufsDirRebuild(SwapDir * sd) +{ + RebuildState *rb; + int clean = 0; + int zero = 0; + FILE *fp; + EVH *func = NULL; + CBDATA_INIT_TYPE(RebuildState); + rb = cbdataAlloc(RebuildState); + rb->sd = sd; + rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; + /* + * If the swap.state file exists in the cache_dir, then + * we'll use storeAufsDirRebuildFromSwapLog(), otherwise we'll + * use storeAufsDirRebuildFromDirectory() to open up each file + * and suck in the meta data. + */ + fp = storeAufsDirOpenTmpSwapLog(sd, &clean, &zero); + if (fp == NULL || zero) { + if (fp != NULL) + fclose(fp); + func = storeAufsDirRebuildFromDirectory; + } else { + func = storeAufsDirRebuildFromSwapLog; + rb->log = fp; + rb->flags.clean = (unsigned int) clean; + } + if (!clean) + rb->flags.need_to_validate = 1; + debug(20, 1) ("Rebuilding storage in %s (%s)\n", + sd->path, clean ? "CLEAN" : "DIRTY"); + store_dirs_rebuilding++; + eventAdd("storeRebuild", func, rb, 0.0, 1); +} + +static void +storeAufsDirCloseTmpSwapLog(SwapDir * sd) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + char *swaplog_path = xstrdup(storeAufsDirSwapLogFile(sd, NULL)); + char *new_path = xstrdup(storeAufsDirSwapLogFile(sd, ".new")); + int fd; + file_close(aioinfo->swaplog_fd); +#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined (_SQUID_MSWIN_) + if (unlink(swaplog_path) < 0) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("storeAufsDirCloseTmpSwapLog: unlink failed"); + } +#endif + if (xrename(new_path, swaplog_path) < 0) { + fatal("storeAufsDirCloseTmpSwapLog: rename failed"); + } + fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("storeAufsDirCloseTmpSwapLog: Failed to open swap log."); + } + safe_free(swaplog_path); + safe_free(new_path); + aioinfo->swaplog_fd = fd; + debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); +} + +static FILE * +storeAufsDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + char *swaplog_path = xstrdup(storeAufsDirSwapLogFile(sd, NULL)); + char *clean_path = xstrdup(storeAufsDirSwapLogFile(sd, ".last-clean")); + char *new_path = xstrdup(storeAufsDirSwapLogFile(sd, ".new")); + struct stat log_sb; + struct stat clean_sb; + FILE *fp; + int fd; + if (stat(swaplog_path, &log_sb) < 0) { + debug(47, 1) ("Cache Dir #%d: No log file\n", sd->index); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return NULL; + } + *zero_flag = log_sb.st_size == 0 ? 1 : 0; + /* close the existing write-only FD */ + if (aioinfo->swaplog_fd >= 0) + file_close(aioinfo->swaplog_fd); + /* open a write-only FD for the new log */ + fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", new_path, xstrerror()); + fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); + } + aioinfo->swaplog_fd = fd; + /* open a read-only stream of the old log */ + fp = fopen(swaplog_path, "r"); + if (fp == NULL) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("Failed to open swap log for reading"); + } + memset(&clean_sb, '\0', sizeof(struct stat)); + if (stat(clean_path, &clean_sb) < 0) + *clean_flag = 0; + else if (clean_sb.st_mtime < log_sb.st_mtime) + *clean_flag = 0; + else + *clean_flag = 1; + safeunlink(clean_path, 1); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return fp; +} + +struct _clean_state { + char *cur; + char *new; + char *cln; + char *outbuf; + off_t outbuf_offset; + int fd; + RemovalPolicyWalker *walker; +}; + +#define CLEAN_BUF_SZ 16384 +/* + * Begin the process to write clean cache state. For AUFS this means + * opening some log files and allocating write buffers. Return 0 if + * we succeed, and assign the 'func' and 'data' return pointers. + */ +static int +storeAufsDirWriteCleanStart(SwapDir * sd) +{ + struct _clean_state *state = xcalloc(1, sizeof(*state)); +#if HAVE_FCHMOD + struct stat sb; +#endif + sd->log.clean.write = NULL; + sd->log.clean.state = NULL; + state->new = xstrdup(storeAufsDirSwapLogFile(sd, ".clean")); + state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (state->fd < 0) { + xfree(state->new); + xfree(state); + return -1; + } + state->cur = xstrdup(storeAufsDirSwapLogFile(sd, NULL)); + state->cln = xstrdup(storeAufsDirSwapLogFile(sd, ".last-clean")); + state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); + state->outbuf_offset = 0; + state->walker = sd->repl->WalkInit(sd->repl); + unlink(state->new); + unlink(state->cln); + debug(20, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n", + state->new, state->fd); +#if HAVE_FCHMOD + if (stat(state->cur, &sb) == 0) + fchmod(state->fd, sb.st_mode); +#endif + sd->log.clean.write = storeAufsDirWriteCleanEntry; + sd->log.clean.state = state; + return 0; +} + +/* + * Get the next entry that is a candidate for clean log writing + */ +const StoreEntry * +storeAufsDirCleanLogNextEntry(SwapDir * sd) +{ + const StoreEntry *entry = NULL; + struct _clean_state *state = sd->log.clean.state; + if (state->walker) + entry = state->walker->Next(state->walker); + return entry; +} + +/* + * "write" an entry to the clean log file. + */ +static void +storeAufsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) +{ + storeSwapLogData s; + static size_t ss = sizeof(storeSwapLogData); + struct _clean_state *state = sd->log.clean.state; + memset(&s, '\0', ss); + s.op = (char) SWAP_LOG_ADD; + s.swap_filen = e->swap_filen; + s.timestamp = e->timestamp; + s.lastref = e->lastref; + s.expires = e->expires; + s.lastmod = e->lastmod; + s.swap_file_sz = e->swap_file_sz; + s.refcount = e->refcount; + s.flags = e->flags; + xmemcpy(&s.key, e->hash.key, MD5_DIGEST_CHARS); + xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); + state->outbuf_offset += ss; + /* buffered write */ + if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { + if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", + state->new, xstrerror()); + debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->new); + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; + } + state->outbuf_offset = 0; + } +} + +static void +storeAufsDirWriteCleanDone(SwapDir * sd) +{ + int fd; + struct _clean_state *state = sd->log.clean.state; + if (NULL == state) + return; + if (state->fd < 0) + return; + state->walker->Done(state->walker); + if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", + state->new, xstrerror()); + debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile " + "not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->new); + } + safe_free(state->outbuf); + /* + * You can't rename open files on Microsoft "operating systems" + * so we have to close before renaming. + */ + storeAufsDirCloseSwapLog(sd); + /* save the fd value for a later test */ + fd = state->fd; + /* rename */ + if (state->fd >= 0) { +#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) + file_close(state->fd); + state->fd = -1; + if (unlink(state->cur) < 0) + debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %s\n", + xstrerror(), state->cur); +#endif + xrename(state->new, state->cur); + } + /* touch a timestamp file if we're not still validating */ + if (store_dirs_rebuilding) + (void) 0; + else if (fd < 0) + (void) 0; + else + file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)); + /* close */ + safe_free(state->cur); + safe_free(state->new); + safe_free(state->cln); + if (state->fd >= 0) + file_close(state->fd); + state->fd = -1; + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; +} + +static void +storeSwapLogDataFree(void *s) +{ + memFree(s, MEM_SWAP_LOG_DATA); +} + +static void +storeAufsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) sd->fsdata; + storeSwapLogData *s = memAllocate(MEM_SWAP_LOG_DATA); + s->op = (char) op; + s->swap_filen = e->swap_filen; + s->timestamp = e->timestamp; + s->lastref = e->lastref; + s->expires = e->expires; + s->lastmod = e->lastmod; + s->swap_file_sz = e->swap_file_sz; + s->refcount = e->refcount; + s->flags = e->flags; + xmemcpy(s->key, e->hash.key, MD5_DIGEST_CHARS); + file_write(aioinfo->swaplog_fd, + -1, + s, + sizeof(storeSwapLogData), + NULL, + NULL, + (FREE *) storeSwapLogDataFree); +} + +static void +storeAufsDirNewfs(SwapDir * sd) +{ + debug(47, 3) ("Creating swap space in %s\n", sd->path); + storeAufsDirCreateDirectory(sd->path, 0); + storeAufsDirCreateSwapSubDirs(sd); +} + +static int +rev_int_sort(const void *A, const void *B) +{ + const int *i1 = A; + const int *i2 = B; + return *i2 - *i1; +} + +static int +storeAufsDirClean(int swap_index) +{ + DIR *dp = NULL; + struct dirent *de = NULL; + LOCAL_ARRAY(char, p1, MAXPATHLEN + 1); + LOCAL_ARRAY(char, p2, MAXPATHLEN + 1); +#if USE_TRUNCATE + struct stat sb; +#endif + int files[20]; + int swapfileno; + int fn; /* same as swapfileno, but with dirn bits set */ + int n = 0; + int k = 0; + int N0, N1, N2; + int D0, D1, D2; + SwapDir *SD; + squidaioinfo_t *aioinfo; + N0 = n_asyncufs_dirs; + D0 = asyncufs_dir_index[swap_index % N0]; + SD = &Config.cacheSwap.swapDirs[D0]; + aioinfo = (squidaioinfo_t *) SD->fsdata; + N1 = aioinfo->l1; + D1 = (swap_index / N0) % N1; + N2 = aioinfo->l2; + D2 = ((swap_index / N0) / N1) % N2; + snprintf(p1, SQUID_MAXPATHLEN, "%s/%02X/%02X", + Config.cacheSwap.swapDirs[D0].path, D1, D2); + debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1); + dp = opendir(p1); + if (dp == NULL) { + if (errno == ENOENT) { + debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1); + if (mkdir(p1, 0777) == 0) + return 0; + } + debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror()); + safeunlink(p1, 1); + return 0; + } + while ((de = readdir(dp)) != NULL && k < 20) { + if (sscanf(de->d_name, "%X", &swapfileno) != 1) + continue; + fn = swapfileno; /* XXX should remove this cruft ! */ + if (storeAufsDirValidFileno(SD, fn, 1)) + if (storeAufsDirMapBitTest(SD, fn)) + if (storeAufsFilenoBelongsHere(fn, D0, D1, D2)) + continue; +#if USE_TRUNCATE + if (!stat(de->d_name, &sb)) + if (sb.st_size == 0) + continue; +#endif + files[k++] = swapfileno; + } + closedir(dp); + if (k == 0) + return 0; + qsort(files, k, sizeof(int), rev_int_sort); + if (k > 10) + k = 10; + for (n = 0; n < k; n++) { + debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]); + snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]); +#if USE_TRUNCATE + truncate(p2, 0); +#else + safeunlink(p2, 0); +#endif + statCounter.swap.files_cleaned++; + } + debug(36, 3) ("Cleaned %d unused files from %s\n", k, p1); + return k; +} + +static void +storeAufsDirCleanEvent(void *unused) +{ + static int swap_index = 0; + int i; + int j = 0; + int n = 0; + /* + * Assert that there are AUFS cache_dirs configured, otherwise + * we should never be called. + */ + assert(n_asyncufs_dirs); + if (NULL == asyncufs_dir_index) { + SwapDir *sd; + squidaioinfo_t *aioinfo; + /* + * Initialize the little array that translates AUFS cache_dir + * number into the Config.cacheSwap.swapDirs array index. + */ + asyncufs_dir_index = xcalloc(n_asyncufs_dirs, sizeof(*asyncufs_dir_index)); + for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) { + sd = &Config.cacheSwap.swapDirs[i]; + if (!storeAufsDirIs(sd)) + continue; + asyncufs_dir_index[n++] = i; + aioinfo = (squidaioinfo_t *) sd->fsdata; + j += (aioinfo->l1 * aioinfo->l2); + } + assert(n == n_asyncufs_dirs); + /* + * Start the storeAufsDirClean() swap_index with a random + * value. j equals the total number of AUFS level 2 + * swap directories + */ + swap_index = (int) (squid_random() % j); + } + if (0 == store_dirs_rebuilding) { + n = storeAufsDirClean(swap_index); + swap_index++; + } + eventAdd("storeDirClean", storeAufsDirCleanEvent, NULL, + 15.0 * exp(-0.25 * n), 1); +} + +static int +storeAufsDirIs(SwapDir * sd) +{ + if (strncmp(sd->type, "awin32", 3) == 0) + return 1; + return 0; +} + +/* + * Does swapfile number 'fn' belong in cachedir #F0, + * level1 dir #F1, level2 dir #F2? + */ +static int +storeAufsFilenoBelongsHere(int fn, int F0, int F1, int F2) +{ + int D1, D2; + int L1, L2; + int filn = fn; + squidaioinfo_t *aioinfo; + assert(F0 < Config.cacheSwap.n_configured); + aioinfo = (squidaioinfo_t *) Config.cacheSwap.swapDirs[F0].fsdata; + L1 = aioinfo->l1; + L2 = aioinfo->l2; + D1 = ((filn / L2) / L2) % L1; + if (F1 != D1) + return 0; + D2 = (filn / L2) % L2; + if (F2 != D2) + return 0; + return 1; +} + +int +storeAufsDirValidFileno(SwapDir * SD, sfileno filn, int flag) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) SD->fsdata; + if (filn < 0) + return 0; + /* + * If flag is set it means out-of-range file number should + * be considered invalid. + */ + if (flag) + if (filn > aioinfo->map->max_n_files) + return 0; + return 1; +} + +void +storeAufsDirMaintain(SwapDir * SD) +{ + StoreEntry *e = NULL; + int removed = 0; + int max_scan; + int max_remove; + double f; + RemovalPurgeWalker *walker; + /* We can't delete objects while rebuilding swap */ + if (store_dirs_rebuilding) { + return; + } else { + f = (double) (SD->cur_size - SD->low_size) / (SD->max_size - SD->low_size); + f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; + max_scan = (int) (f * 400.0 + 100.0); + max_remove = (int) (f * 70.0 + 10.0); + /* + * This is kinda cheap, but so we need this priority hack? + */ + } + debug(20, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", + f, max_scan, max_remove); + walker = SD->repl->PurgeInit(SD->repl, max_scan); + while (1) { + if (SD->cur_size < SD->low_size) + break; + if (removed >= max_remove) + break; + e = walker->Next(walker); + if (!e) + break; /* no more objects */ + removed++; + storeRelease(e); + } + walker->Done(walker); + debug(20, (removed ? 2 : 3)) ("storeUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", + SD->path, removed, max_remove, f, max_scan); +} + +/* + * storeAufsDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. AUFS filesystems will + * happily store anything as long as the LRU time isn't too small. + */ +int +storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + int loadav; + int ql; + +#if OLD_UNUSED_CODE + if (storeAufsDirExpiredReferenceAge(SD) < 300) { + debug(20, 3) ("storeAufsDirCheckObj: NO: LRU Age = %d\n", + storeAufsDirExpiredReferenceAge(SD)); + /* store_check_cachable_hist.no.lru_age_too_low++; */ + return -1; + } +#endif + ql = aioQueueSize(); + if (ql == 0) + loadav = 0; + loadav = ql * 1000 / MAGIC1; + debug(41, 9) ("storeAufsDirCheckObj: load=%d\n", loadav); + return loadav; +} + +/* + * storeAufsDirRefObj + * + * This routine is called whenever an object is referenced, so we can + * maintain replacement information within the storage fs. + */ +void +storeAufsDirRefObj(SwapDir * SD, StoreEntry * e) +{ + debug(1, 3) ("storeAufsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, + e->swap_filen); + if (SD->repl->Referenced) + SD->repl->Referenced(SD->repl, e, &e->repl); +} + +/* + * storeAufsDirUnrefObj + * This routine is called whenever the last reference to an object is + * removed, to maintain replacement information within the storage fs. + */ +void +storeAufsDirUnrefObj(SwapDir * SD, StoreEntry * e) +{ + debug(1, 3) ("storeAufsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, + e->swap_filen); + if (SD->repl->Dereferenced) + SD->repl->Dereferenced(SD->repl, e, &e->repl); +} + +/* + * storeAufsDirUnlinkFile + * + * This routine unlinks a file and pulls it out of the bitmap. + * It used to be in storeAufsUnlink(), however an interface change + * forced this bit of code here. Eeek. + */ +void +storeAufsDirUnlinkFile(SwapDir * SD, sfileno f) +{ + debug(79, 3) ("storeAufsDirUnlinkFile: unlinking fileno %08X\n", f); + /* storeAufsDirMapBitReset(SD, f); */ +#if USE_TRUNCATE_NOT_UNLINK + aioTruncate(storeAufsDirFullPath(SD, f, NULL), NULL, NULL); +#else + aioUnlink(storeAufsDirFullPath(SD, f, NULL), NULL, NULL); +#endif +} + +/* + * Add and remove the given StoreEntry from the replacement policy in + * use. + */ + +void +storeAufsDirReplAdd(SwapDir * SD, StoreEntry * e) +{ + debug(20, 4) ("storeAufsDirReplAdd: added node %p to dir %d\n", e, + SD->index); + SD->repl->Add(SD->repl, e, &e->repl); +} + + +void +storeAufsDirReplRemove(StoreEntry * e) +{ + SwapDir *SD = INDEXSD(e->swap_dirn); + debug(20, 4) ("storeAufsDirReplRemove: remove node %p from dir %d\n", e, + SD->index); + SD->repl->Remove(SD->repl, e, &e->repl); +} + + + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +void +storeAufsDirStats(SwapDir * SD, StoreEntry * sentry) +{ + squidaioinfo_t *aioinfo = SD->fsdata; + int totl_kb = 0; + int free_kb = 0; + int totl_in = 0; + int free_in = 0; + int x; + storeAppendPrintf(sentry, "First level subdirectories: %d\n", aioinfo->l1); + storeAppendPrintf(sentry, "Second level subdirectories: %d\n", aioinfo->l2); + storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); + storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); + storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", + 100.0 * SD->cur_size / SD->max_size); + storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", + aioinfo->map->n_files_in_map, aioinfo->map->max_n_files, + percent(aioinfo->map->n_files_in_map, aioinfo->map->max_n_files)); + x = storeDirGetUFSStats(SD->path, &totl_kb, &free_kb, &totl_in, &free_in); + if (0 == x) { + storeAppendPrintf(sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n", + totl_kb - free_kb, + totl_kb, + percent(totl_kb - free_kb, totl_kb)); + storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n", + totl_in - free_in, + totl_in, + percent(totl_in - free_in, totl_in)); + } + storeAppendPrintf(sentry, "Flags:"); + if (SD->flags.selected) + storeAppendPrintf(sentry, " SELECTED"); + if (SD->flags.read_only) + storeAppendPrintf(sentry, " READ-ONLY"); + storeAppendPrintf(sentry, "\n"); +} + +static struct cache_dir_option options[] = +{ +#if NOT_YET_DONE + {"L1", storeAufsDirParseL1}, + {"L2", storeAufsDirParseL2}, +#endif + {NULL, NULL} +}; + +/* + * storeAufsDirReconfigure + * + * This routine is called when the given swapdir needs reconfiguring + */ +static void +storeAufsDirReconfigure(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeAufsDirReconfigure: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeAufsDirReconfigure: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeAufsDirReconfigure: invalid level 2 directories value"); + + /* just reconfigure it */ + if (size == sd->max_size) + debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", + path, size); + else + debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", + path, size); + sd->max_size = size; + + parse_cachedir_options(sd, options, 0); + + return; +} + +void +storeAufsDirDump(StoreEntry * entry, SwapDir * s) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) s->fsdata; + storeAppendPrintf(entry, " %d %d %d", + s->max_size >> 10, + aioinfo->l1, + aioinfo->l2); + dump_cachedir_options(entry, options, s); +} + +/* + * Only "free" the filesystem specific stuff here + */ +static void +storeAufsDirFree(SwapDir * s) +{ + squidaioinfo_t *aioinfo = (squidaioinfo_t *) s->fsdata; + if (aioinfo->swaplog_fd > -1) { + file_close(aioinfo->swaplog_fd); + aioinfo->swaplog_fd = -1; + } + filemapFreeMemory(aioinfo->map); + xfree(aioinfo); + s->fsdata = NULL; /* Will aid debugging... */ +} + +char * +storeAufsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath) +{ + LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); + squidaioinfo_t *aioinfo = (squidaioinfo_t *) SD->fsdata; + int L1 = aioinfo->l1; + int L2 = aioinfo->l2; + if (!fullpath) + fullpath = fullfilename; + fullpath[0] = '\0'; + snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X", + SD->path, + ((filn / L2) / L2) % L1, + (filn / L2) % L2, + filn); + return fullpath; +} + +/* + * storeAufsCleanupDoubleCheck + * + * This is called by storeCleanup() if -S was given on the command line. + */ +static int +storeAufsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) +{ +#ifndef _SQUID_MSWIN_ + struct stat sb; + if (stat(storeAufsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { + debug(20, 0) ("storeAufsCleanupDoubleCheck: MISSING SWAP FILE\n"); + debug(20, 0) ("storeAufsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); + debug(20, 0) ("storeAufsCleanupDoubleCheck: PATH %s\n", + storeAufsDirFullPath(sd, e->swap_filen, NULL)); + storeEntryDump(e, 0); + return -1; + } + if (e->swap_file_sz != sb.st_size) { + debug(20, 0) ("storeAufsCleanupDoubleCheck: SIZE MISMATCH\n"); + debug(20, 0) ("storeAufsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); + debug(20, 0) ("storeAufsCleanupDoubleCheck: PATH %s\n", + storeAufsDirFullPath(sd, e->swap_filen, NULL)); + debug(20, 0) ("storeAufsCleanupDoubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n", + (long int) e->swap_file_sz, (long int) sb.st_size); + storeEntryDump(e, 0); + return -1; + } +#endif + return 0; +} + +/* + * storeAufsDirParse * + * Called when a *new* fs is being setup. + */ +static void +storeAufsDirParse(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + squidaioinfo_t *aioinfo; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeAufsDirParse: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeAufsDirParse: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeAufsDirParse: invalid level 2 directories value"); + + aioinfo = xmalloc(sizeof(squidaioinfo_t)); + if (aioinfo == NULL) + fatal("storeAufsDirParse: couldn't xmalloc() squidaioinfo_t!\n"); + + sd->index = index; + sd->path = xstrdup(path); + sd->max_size = size; + sd->fsdata = aioinfo; + aioinfo->l1 = l1; + aioinfo->l2 = l2; + aioinfo->swaplog_fd = -1; + aioinfo->map = NULL; /* Debugging purposes */ + aioinfo->suggest = 0; + sd->init = storeAufsDirInit; + sd->newfs = storeAufsDirNewfs; + sd->dump = storeAufsDirDump; + sd->freefs = storeAufsDirFree; + sd->dblcheck = storeAufsCleanupDoubleCheck; + sd->statfs = storeAufsDirStats; + sd->maintainfs = storeAufsDirMaintain; + sd->checkobj = storeAufsDirCheckObj; + sd->refobj = storeAufsDirRefObj; + sd->unrefobj = storeAufsDirUnrefObj; + sd->callback = aioCheckCallbacks; + sd->sync = aioSync; + sd->obj.create = storeAufsCreate; + sd->obj.open = storeAufsOpen; + sd->obj.close = storeAufsClose; + sd->obj.read = storeAufsRead; + sd->obj.write = storeAufsWrite; + sd->obj.unlink = storeAufsUnlink; + sd->log.open = storeAufsDirOpenSwapLog; + sd->log.close = storeAufsDirCloseSwapLog; + sd->log.write = storeAufsDirSwapLog; + sd->log.clean.start = storeAufsDirWriteCleanStart; + sd->log.clean.nextentry = storeAufsDirCleanLogNextEntry; + sd->log.clean.done = storeAufsDirWriteCleanDone; + + parse_cachedir_options(sd, options, 0); + + /* Initialise replacement policy stuff */ + sd->repl = createRemovalPolicy(Config.replPolicy); +} + +/* + * Initial setup / end destruction + */ +static void +storeAufsDirDone(void) +{ + aioDone(); + memPoolDestroy(squidaio_state_pool); + memPoolDestroy(aufs_qread_pool); + memPoolDestroy(aufs_qwrite_pool); + asyncufs_initialised = 0; +} + +void +storeFsSetup_awin32(storefs_entry_t * storefs) +{ + assert(!asyncufs_initialised); + storefs->parsefunc = storeAufsDirParse; + storefs->reconfigurefunc = storeAufsDirReconfigure; + storefs->donefunc = storeAufsDirDone; + squidaio_state_pool = memPoolCreate("AUFS IO State data", sizeof(squidaiostate_t)); + aufs_qread_pool = memPoolCreate("AUFS Queued read data", + sizeof(queued_read)); + aufs_qwrite_pool = memPoolCreate("AUFS Queued write data", + sizeof(queued_write)); + + asyncufs_initialised = 1; + aioInit(); +} --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/fs/awin32/store_io_aufs.c Wed Feb 14 00:57:27 2007 @@ -0,0 +1,446 @@ + +/* + * DEBUG 78 + */ + +#include "squid.h" +#include "store_asyncufs.h" + +#if ASYNC_READ +static AIOCB storeAufsReadDone; +#else +static DRCB storeAufsReadDone; +#endif +#if ASYNC_WRITE +static AIOCB storeAufsWriteDone; +#else +static DWCB storeAufsWriteDone; +#endif +static void storeAufsIOCallback(storeIOState * sio, int errflag); +static AIOCB storeAufsOpenDone; +static int storeAufsSomethingPending(storeIOState *); +static int storeAufsKickWriteQueue(storeIOState * sio); +static CBDUNL storeAufsIOFreeEntry; + +CBDATA_TYPE(storeIOState); + +/* === PUBLIC =========================================================== */ + +/* open for reading */ +storeIOState * +storeAufsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + sfileno f = e->swap_filen; + char *path = storeAufsDirFullPath(SD, f, NULL); + storeIOState *sio; +#if !ASYNC_OPEN + int fd; +#endif + debug(78, 3) ("storeAufsOpen: fileno %08X\n", f); + /* + * we should detect some 'too many files open' condition and return + * NULL here. + */ +#ifdef MAGIC2 + if (aioQueueSize() > MAGIC2) + return NULL; +#endif +#if !ASYNC_OPEN + fd = file_open(path, O_RDONLY | O_BINARY); + if (fd < 0) { + debug(78, 3) ("storeAufsOpen: got failude (%d)\n", errno); + return NULL; + } +#endif + CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(squidaio_state_pool); + ((squidaiostate_t *) (sio->fsstate))->fd = -1; + ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->mode = O_RDONLY; + sio->callback = callback; + sio->callback_data = callback_data; + sio->e = e; + cbdataLock(callback_data); + Opening_FD++; +#if ASYNC_OPEN + aioOpen(path, O_RDONLY | O_BINARY, 0644, storeAufsOpenDone, sio); +#else + storeAufsOpenDone(fd, sio, fd, 0); +#endif + return sio; +} + +/* open for creating */ +storeIOState * +storeAufsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) +{ + char *path; + storeIOState *sio; + sfileno filn; + sdirno dirn; +#if !ASYNC_CREATE + int fd; +#endif + + /* Allocate a number */ + dirn = SD->index; + filn = storeAufsDirMapBitAllocate(SD); + path = storeAufsDirFullPath(SD, filn, NULL); + + debug(78, 3) ("storeAufsCreate: fileno %08X\n", filn); + /* + * we should detect some 'too many files open' condition and return + * NULL here. + */ +#ifdef MAGIC2 + if (aioQueueSize() > MAGIC2) + return NULL; +#endif +#if !ASYNC_CREATE + fd = file_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (fd < 0) { + debug(78, 3) ("storeAufsCreate: got failude (%d)\n", errno); + return NULL; + } +#endif + CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(squidaio_state_pool); + ((squidaiostate_t *) (sio->fsstate))->fd = -1; + ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; + sio->swap_filen = filn; + sio->swap_dirn = dirn; + sio->mode = O_WRONLY | O_BINARY; + sio->callback = callback; + sio->callback_data = callback_data; + sio->e = (StoreEntry *) e; + cbdataLock(callback_data); + Opening_FD++; +#if ASYNC_CREATE + aioOpen(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644, storeAufsOpenDone, sio); +#else + storeAufsOpenDone(fd, sio, fd, 0); +#endif + + /* now insert into the replacement policy */ + storeAufsDirReplAdd(SD, e); + return sio; + +} + + + +/* Close */ +void +storeAufsClose(SwapDir * SD, storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(78, 3) ("storeAufsClose: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + if (storeAufsSomethingPending(sio)) { + aiostate->flags.close_request = 1; + return; + } + storeAufsIOCallback(sio, DISK_OK); +} + + +/* Read */ +void +storeAufsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + assert(sio->read.callback == NULL); + assert(sio->read.callback_data == NULL); + assert(!aiostate->flags.reading); + if (aiostate->fd < 0) { + struct _queued_read *q; + debug(78, 3) ("storeAufsRead: queueing read because FD < 0\n"); + assert(aiostate->flags.opening); + assert(aiostate->pending_reads == NULL); + q = memPoolAlloc(aufs_qread_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->callback = callback; + q->callback_data = callback_data; + linklistPush(&(aiostate->pending_reads), q); + return; + } + sio->read.callback = callback; + sio->read.callback_data = callback_data; + aiostate->read_buf = buf; + cbdataLock(callback_data); + debug(78, 3) ("storeAufsRead: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + sio->offset = offset; + aiostate->flags.reading = 1; +#if ASYNC_READ + aioRead(aiostate->fd, offset, buf, size, storeAufsReadDone, sio); +#else + file_read(aiostate->fd, offset, buf, size, storeAufsReadDone, sio); +#endif +} + + +/* Write */ +void +storeAufsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(78, 3) ("storeAufsWrite: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + if (aiostate->fd < 0) { + /* disk file not opened yet */ + struct _queued_write *q; + assert(aiostate->flags.opening); + q = memPoolAlloc(aufs_qwrite_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->free_func = free_func; + linklistPush(&(aiostate->pending_writes), q); + return; + } +#if ASYNC_WRITE + if (aiostate->flags.writing) { + struct _queued_write *q; + debug(78, 3) ("storeAufsWrite: queuing write\n"); + q = memPoolAlloc(aufs_qwrite_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->free_func = free_func; + linklistPush(&(aiostate->pending_writes), q); + return; + } + aiostate->flags.writing = 1; + aioWrite(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, + free_func); +#else + file_write(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, + free_func); +#endif +} + +/* Unlink */ +void +storeAufsUnlink(SwapDir * SD, StoreEntry * e) +{ + debug(78, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", SD->index, e->swap_filen); + storeAufsDirReplRemove(e); + storeAufsDirMapBitReset(SD, e->swap_filen); + storeAufsDirUnlinkFile(SD, e->swap_filen); +} + +/* === STATIC =========================================================== */ + +static int +storeAufsKickWriteQueue(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + struct _queued_write *q = linklistShift(&aiostate->pending_writes); + if (NULL == q) + return 0; + debug(78, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n", + (long int) q->size); + storeAufsWrite(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->free_func); + memPoolFree(aufs_qwrite_pool, q); + return 1; +} + +static int +storeAufsKickReadQueue(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + struct _queued_read *q = linklistShift(&(aiostate->pending_reads)); + if (NULL == q) + return 0; + debug(78, 3) ("storeAufsKickReadQueue: reading queued request of %ld bytes\n", + (long int) q->size); + storeAufsRead(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->callback, q->callback_data); + memPoolFree(aufs_qread_pool, q); + return 1; +} + +static void +storeAufsOpenDone(int unused, void *my_data, int fd, int errflag) +{ + storeIOState *sio = my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(78, 3) ("storeAufsOpenDone: FD %d, errflag %d\n", fd, errflag); + Opening_FD--; + aiostate->flags.opening = 0; + if (errflag || fd < 0) { + errno = errflag; + debug(78, 0) ("storeAufsOpenDone: %s\n", xstrerror()); + debug(78, 1) ("\t%s\n", storeAufsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); + storeAufsIOCallback(sio, DISK_ERROR); + return; + } + store_open_disk_fd++; + aiostate->fd = fd; + commSetCloseOnExec(fd); + fd_open(fd, FD_FILE, storeAufsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); + if (sio->mode == O_WRONLY) + storeAufsKickWriteQueue(sio); + else if (sio->mode == O_RDONLY) + storeAufsKickReadQueue(sio); + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); + debug(78, 3) ("storeAufsOpenDone: exiting\n"); +} + +#if ASYNC_READ +static void +storeAufsReadDone(int fd, void *my_data, int len, int errflag) +#else +static void +storeAufsReadDone(int fd, int errflag, size_t len, void *my_data) +#endif +{ + storeIOState *sio = my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + STRCB *callback = sio->read.callback; + void *their_data = sio->read.callback_data; + ssize_t rlen; + debug(78, 3) ("storeAufsReadDone: dirno %d, fileno %08X, FD %d, len %d\n", + sio->swap_dirn, sio->swap_filen, fd, len); + aiostate->flags.inreaddone = 1; + aiostate->flags.reading = 0; + if (errflag) { + debug(78, 3) ("storeAufsReadDone: got failure (%d)\n", errflag); + rlen = -1; + } else { + rlen = (ssize_t) len; + sio->offset += len; + } +#if ASYNC_READ + /* translate errflag from errno to Squid disk error */ + errno = errflag; + if (errflag) + errflag = DISK_ERROR; + else + errflag = DISK_OK; +#else + if (errflag == DISK_EOF) + errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */ +#endif + assert(callback); + assert(their_data); + sio->read.callback = NULL; + sio->read.callback_data = NULL; + if (cbdataValid(their_data)) + callback(their_data, aiostate->read_buf, rlen); + cbdataUnlock(their_data); + aiostate->flags.inreaddone = 0; + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); +} + +#if ASYNC_WRITE +static void +storeAufsWriteDone(int fd, void *my_data, int len, int errflag) +#else +static void +storeAufsWriteDone(int fd, int errflag, size_t len, void *my_data) +#endif +{ + static int loop_detect = 0; + storeIOState *sio = my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(78, 3) ("storeAufsWriteDone: dirno %d, fileno %08X, FD %d, len %ld, err=%d\n", + sio->swap_dirn, sio->swap_filen, fd, (long int) len, errflag); +#if ASYNC_WRITE + /* Translate from errno to Squid disk error */ + errno = errflag; + if (errflag) + errflag = errno == ENOSP ? DISK_NO_SPACE_LEFT : DISK_ERROR; + else + errflag = DISK_OK; +#endif + assert(++loop_detect < 10); + aiostate->flags.writing = 0; + if (errflag) { + debug(78, 0) ("storeAufsWriteDone: got failure (%d)\n", errflag); + storeAufsIOCallback(sio, errflag); + loop_detect--; + return; + } + sio->offset += len; +#if ASYNC_WRITE + if (!storeAufsKickWriteQueue(sio)) + 0; + else if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); +#else + if (!aiostate->flags.write_kicking) { + aiostate->flags.write_kicking = 1; + while (storeAufsKickWriteQueue(sio)) + (void) 0; + aiostate->flags.write_kicking = 0; + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); + } +#endif + loop_detect--; +} + +static void +storeAufsIOCallback(storeIOState * sio, int errflag) +{ + STIOCB *callback = sio->callback; + void *their_data = sio->callback_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + int fd = aiostate->fd; + debug(78, 3) ("storeAufsIOCallback: errflag=%d\n", errflag); + sio->callback = NULL; + sio->callback_data = NULL; + debug(78, 3) ("%s:%d\n", __FILE__, __LINE__); + if (callback) + if (NULL == their_data || cbdataValid(their_data)) + callback(their_data, errflag, sio); + debug(78, 3) ("%s:%d\n", __FILE__, __LINE__); + cbdataUnlock(their_data); + aiostate->fd = -1; + cbdataFree(sio); + if (fd < 0) + return; + debug(78, 3) ("%s:%d\n", __FILE__, __LINE__); + aioClose(fd); + fd_close(fd); + store_open_disk_fd--; + debug(78, 3) ("%s:%d\n", __FILE__, __LINE__); +} + + +static int +storeAufsSomethingPending(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + if (aiostate->flags.reading) + return 1; + if (aiostate->flags.writing) + return 1; + if (aiostate->flags.opening) + return 1; + if (aiostate->flags.inreaddone) + return 1; + return 0; +} + + +/* + * Clean up references from the SIO before it gets released. + * The actuall SIO is managed by cbdata so we do not need + * to bother with that. + */ +static void +storeAufsIOFreeEntry(void *sio) +{ + memPoolFree(squidaio_state_pool, ((storeIOState *) sio)->fsstate); +} Index: squid/src/fs/ufs/store_dir_ufs.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/fs/ufs/store_dir_ufs.c,v retrieving revision 1.21.6.1 retrieving revision 1.21.6.1.4.1 diff -u -r1.21.6.1 -r1.21.6.1.4.1 --- squid/src/fs/ufs/store_dir_ufs.c 20 Feb 2002 02:49:04 -0000 1.21.6.1 +++ squid/src/fs/ufs/store_dir_ufs.c 14 Mar 2002 20:23:47 -0000 1.21.6.1.4.1 @@ -416,7 +416,12 @@ rb->sd->path, rb->counts.scancount); debug(20, 9) ("file_in: fd=%d %08X\n", fd, filn); statCounter.syscalls.disk.reads++; - if (read(fd, hdr_buf, SM_PAGE_SIZE) < 0) { +#ifdef _SQUID_MSWIN_ + if (fread(hdr_buf, 1, SM_PAGE_SIZE, fd_table[fd].fbuf) == 0 + && ferror(fd_table[fd].fbuf)) { +#else + if (read(fd, hdr_buf, SM_PAGE_SIZE) < 0) { +#endif debug(20, 1) ("storeUfsDirRebuildFromDirectory: read(FD %d): %s\n", fd, xstrerror()); file_close(fd); @@ -860,7 +865,7 @@ char *new_path = xstrdup(storeUfsDirSwapLogFile(sd, ".new")); int fd; file_close(ufsinfo->swaplog_fd); -#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) +#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined (_SQUID_MSWIN_) if (unlink(swaplog_path) < 0) { debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); fatal("storeUfsDirCloseTmpSwapLog: unlink failed"); @@ -915,7 +920,7 @@ debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); fatal("Failed to open swap log for reading"); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_BINARY); #endif memset(&clean_sb, '\0', sizeof(struct stat)); @@ -967,6 +972,9 @@ state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); state->outbuf_offset = 0; state->walker = sd->repl->WalkInit(sd->repl); +#if !(defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_)) || defined (_SQUID_MSWIN_) + unlink(state->new); +#endif unlink(state->cln); debug(20, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n", state->new, state->fd); @@ -1016,7 +1024,11 @@ state->outbuf_offset += ss; /* buffered write */ if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { +#ifdef _SQUID_MSWIN_ + if (fwrite(state->outbuf, 1, state->outbuf_offset, fd_table[state->fd].fbuf) < state->outbuf_offset) { +#else if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { +#endif debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", state->new, xstrerror()); debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n"); @@ -1026,14 +1038,17 @@ safe_free(state); sd->log.clean.state = NULL; sd->log.clean.write = NULL; - } - state->outbuf_offset = 0; + } else + state->outbuf_offset = 0; } } static void storeUfsDirWriteCleanDone(SwapDir * sd) { +#ifdef _SQUID_MSWIN_ + FILE *fbuf; +#endif int fd; struct _clean_state *state = sd->log.clean.state; if (NULL == state) @@ -1041,7 +1056,13 @@ if (state->fd < 0) return; state->walker->Done(state->walker); +#ifdef _SQUID_MSWIN_ + fbuf=fd_table[state->fd].fbuf; + fwrite(state->outbuf, 1, state->outbuf_offset, fbuf); + if (ferror(fbuf) || feof(fbuf)){ +#else if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { +#endif debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", state->new, xstrerror()); debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile " @@ -1060,7 +1081,7 @@ fd = state->fd; /* rename */ if (state->fd >= 0) { -#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) +#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined (_SQUID_MSWIN_) file_close(state->fd); state->fd = -1; if (unlink(state->cur) < 0) @@ -1570,6 +1591,7 @@ static int storeUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) { +#ifndef _SQUID_MSWIN_ struct stat sb; if (stat(storeUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { debug(20, 0) ("storeUfsCleanupDoubleCheck: MISSING SWAP FILE\n"); @@ -1589,6 +1611,7 @@ storeEntryDump(e, 0); return -1; } +#endif return 0; }