Overview
SHA1 Hash: | 8372cc0b8125d2c52332021a3e0a2cbbf9b2506f |
---|---|
Date: | 2007-09-22 18:34:49 |
User: | jnc |
Comment: | Socket operations now functional in Win32 port. Added quotes around the filename portion of the command to edit thus working of windows in paths where the temp directory contains spaces. Added -all flag to clean command. If not specified each file is prompted for before removing. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified Makefile from [32e9920702] to [7035415b04].
@@ -34,15 +34,15 @@ # other dependencies. We sometimes add the -static option here # so that we can build a static executable that will run in a # chroot jail. # #LIB = -lz -LIB = -lz -lwsock32 +LIB = -lz -lws2_32 #### Tcl shell for use in running the fossil testsuite. # TCLSH = tclsh # You should not need to change anything below this line ############################################################################### include $(SRCDIR)/main.mk
Modified src/cgi.c from [1e442c1fca] to [57f4d7daa3].
@@ -28,11 +28,11 @@ ** decode strings in HTML or HTTP. */ #include "config.h" #ifdef __MINGW32__ # include <windows.h> /* for Sleep once server works again */ -# include <winsock.h> /* socket operations */ +# include <winsock2.h> /* socket operations */ # define sleep Sleep /* windows does not have sleep, but Sleep */ #else # include <sys/socket.h> # include <netinet/in.h> # include <arpa/inet.h>
Modified src/checkin.c from [08fa2df4cf] to [39235e7847].
@@ -162,18 +162,24 @@ db_finalize(&q); } /* ** COMMAND: clean -** Usage: %fossil clean +** Usage: %fossil clean ?-all ** Delete all "extra" files in the source tree. "Extra" files are ** files that are not officially part of the checkout. See also -** the "extra" command. +** the "extra" command. This operation cannot be undone. +** +** You will be prompted before removing each file. If you are +** sure you wish to remove all "extra" files you can specify the +** optional -all flag. */ void clean_cmd(void){ + int allFlag; Blob path; Stmt q; + allFlag = find_option("all","a",0)!=0; db_must_be_within_tree(); db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); chdir(g.zLocalRoot); blob_zero(&path); vfile_scan(0, &path); @@ -180,11 +186,23 @@ db_prepare(&q, "SELECT %Q || x FROM sfile" " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')" " ORDER BY 1", g.zLocalRoot); while( db_step(&q)==SQLITE_ROW ){ - unlink(db_column_text(&q, 0)); + if( allFlag ){ + unlink(db_column_text(&q, 0)); + continue; + } + + Blob ans; + char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ", + db_column_text(&q, 0)); + blob_zero(&ans); + prompt_user(prompt, &ans); + if( blob_str(&ans)[0]=='y' ){ + unlink(db_column_text(&q, 0)); + } } db_finalize(&q); } /* @@ -218,11 +236,11 @@ zEditor = "ed"; } zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", g.zLocalRoot); blob_write_to_file(&text, zFile); - zCmd = mprintf("%s %s", zEditor, zFile); + zCmd = mprintf("%s \"%s\"", zEditor, zFile); printf("%s\n", zCmd); if( system(zCmd) ){ fossil_panic("editor aborted"); } blob_reset(&text);
Modified src/http.c from [02357907c7] to [54410d4f2b].
@@ -25,11 +25,11 @@ */ #include "config.h" #include "http.h" #ifdef __MINGW32__ # include <windows.h> -# include <winsock.h> +# include <winsock2.h> #else # include <arpa/inet.h> # include <sys/socket.h> # include <netdb.h> # include <netinet/in.h> @@ -39,24 +39,34 @@ #include <signal.h> /* ** Persistent information about the HTTP connection. */ -static FILE *pSocket = 0; /* The socket on which we talk to the server */ #ifdef __MINGW32__ static WSADATA ws_info; +static int pSocket = 0; /* The socket on which we talk to the server on */ +#else +static FILE *pSocket = 0; /* The socket filehandle on which we talk to the server */ #endif +/* +** Winsock must be initialize before use. This helper method allows us to +** always call ws_init in our code regardless of platform but only actually +** initialize winsock on the windows platform. +*/ static void ws_init(){ #ifdef __MINGW32__ - if (WSAStartup(MAKEWORD(1,1), &ws_info) != 0){ + if (WSAStartup(MAKEWORD(2,0), &ws_info) != 0){ fossil_panic("can't initialize winsock"); } #endif } +/* +** Like ws_init, winsock must also be cleaned up after. +*/ static void ws_cleanup(){ #ifdef __MINGW32__ WSACleanup(); #endif } @@ -68,12 +78,13 @@ static int http_open_socket(void){ static struct sockaddr_in addr; /* The server address */ static int addrIsInit = 0; /* True once addr is initialized */ int s; - if( !addrIsInit ){ - ws_init(); + ws_init(); + + if( !addrIsInit ){ addr.sin_family = AF_INET; addr.sin_port = htons(g.urlPort); *(int*)&addr.sin_addr = inet_addr(g.urlName); if( -1 == *(int*)&addr.sin_addr ){ @@ -101,15 +112,64 @@ fossil_panic("cannot create a socket"); } if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){ fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort); } - pSocket = fdopen(s,"r+"); -#ifndef __MINGW32__ +#ifdef __MINGW32__ + pSocket = s; +#else + pSocket = fdopen(s,"r+"); signal(SIGPIPE, SIG_IGN); #endif return 0; +} + +/* +** Read the socket until a newline '\n' is found. Return the number +** of characters read. pSockId contains the socket handel. pOut +** contains a pointer to the buffer to write to. pOutSize contains +** the maximum size of the line that pOut can handle. +*/ +static int socket_recv_line(int pSockId, char* pOut, int pOutSize){ + int received=0; + char letter; + memset(pOut,0,pOutSize); + for(; received<pOutSize-1;received++){ + if( recv(pSockId,(char*)&letter,1,0)>0 ){ + pOut[received]=letter; + if( letter=='\n' ){ + break; + } + }else{ + break; + } + } + return received; +} + +/* +** Initialize a blob to the data on an input socket. return +** the number of bytes read into the blob. Any prior content +** of the blob is discarded, not freed. +** +** The function was placed here in http.c due to it's socket +** nature and we did not want to introduce socket headers into +** the socket netural blob.c file. +*/ +int socket_read_blob(Blob *pBlob, int pSockId, int nToRead){ + int i=0,read=0; + char rbuf[50]; + blob_zero(pBlob); + while ( i<nToRead ){ + read = recv(pSockId, rbuf, 50, 0); + i += read; + if( read<0 ){ + return 0; + } + blob_append(pBlob, rbuf, read); + } + return blob_size(pBlob); } /* ** Make a single attempt to talk to the server. Return TRUE on success ** and FALSE on a failure. @@ -120,40 +180,78 @@ ** ** If an error occurs, this routine return false, resets pReply and ** closes the persistent connection, if any. */ static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){ - int rc; - int closeConnection; + int closeConnection=1; /* default to closing the connection */ + int rc; int iLength; int iHttpVersion; int i; int nRead; char zLine[2000]; if( pSocket==0 && http_open_socket() ){ return 0; } + iLength = -1; +#ifdef __MINGW32__ + /* + ** Use recv/send on the windows platform as winsock does not allow + ** sockets to be used as FILE handles, thus fdopen, fwrite, fgets + ** does not function on windows for sockets. + */ + rc = send(pSocket, blob_buffer(pHeader), blob_size(pHeader), 0); + if( rc!=blob_size(pHeader) ) goto write_err; + rc = send(pSocket, blob_buffer(pPayload), blob_size(pPayload), 0); + if( rc!=blob_size(pPayload) ) goto write_err; + + /* Read the response */ + while( socket_recv_line(pSocket, zLine, 2000) ){ + for( i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++ ){} + if( i==0 ) break; + zLine[i] = 0; + if( strncasecmp(zLine, "http/1.", 7)==0 ){ + if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err; + if( rc!=200 ) goto write_err; + if( iHttpVersion==0 ){ + closeConnection = 1; + }else{ + closeConnection = 0; + } + } else if( strncasecmp(zLine, "content-length:", 15)==0 ){ + iLength = atoi(&zLine[16]); + }else if( strncasecmp(zLine, "connection:", 11)==0 ){ + for(i=12; isspace(zLine[i]); i++){} + if( zLine[i]=='c' || zLine[i]=='C' ){ + closeConnection = 1; + }else if( zLine[i]=='k' || zLine[i]=='K' ){ + closeConnection = 0; + } + } + } + if( iLength<0 ) goto write_err; + nRead = socket_read_blob(pReply, pSocket, iLength); +#else rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket); if( rc!=blob_size(pHeader) ) goto write_err; rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket); if( rc!=blob_size(pPayload) ) goto write_err; if( fflush(pSocket) ) goto write_err; if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err; if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err; if( rc!=200 ) goto write_err; if( iHttpVersion==0 ){ - closeConnection = 1; + closeConnection = 1; /* Connection: close */ }else{ - closeConnection = 0; - } - iLength = -1; + closeConnection = 0; /* Connection: keep-alive */ + } while( fgets(zLine, sizeof(zLine), pSocket) ){ for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){} if( i==0 ) break; zLine[i] = 0; - if( strncasecmp(zLine, "content-length:",15)==0 ){ + if( strncasecmp(zLine,"content-length:",15)==0 ){ iLength = atoi(&zLine[16]); }else if( strncasecmp(zLine, "connection:", 11)==0 ){ for(i=12; isspace(zLine[i]); i++){} if( zLine[i]=='c' || zLine[i]=='C' ){ closeConnection = 1; /* Connection: close */ @@ -162,10 +260,11 @@ } } } if( iLength<0 ) goto write_err; nRead = blob_read_from_channel(pReply, pSocket, iLength); +#endif if( nRead!=iLength ){ blob_reset(pReply); goto write_err; } if( closeConnection ){ @@ -287,10 +386,21 @@ /* ** Make sure the socket to the HTTP server is closed */ void http_close(void){ if( pSocket ){ +#ifdef __MINGW32__ + closesocket(pSocket); +#else fclose(pSocket); - pSocket = 0; - ws_cleanup(); +#endif + pSocket = 0; } + /* + ** This is counter productive. Each time we open a connection we initialize + ** winsock and then when closing we cleanup. It would be better to + ** initialize winsock once at application start when we know we are going to + ** use the socket interface and then cleanup once at application exit when + ** we are all done with all socket operations. + */ + ws_cleanup(); }
Modified win32.txt from [a31e062bd3] to [f8b38cdb44].
@@ -11,39 +11,26 @@ Download/compile/install zlib (configure --prefix=/mingw) Download/compile/install tclsh (configure --prefix=/) (for tests) All commands were issued in the MSYS shell, not a cmd.exe - - Outstanding Issues: ---------------------------------------------------------------------- * server is totally non-functional - #if/#end'd out of the code -* all path operations are defunct -* remote network operations are reporting: can't resolve host name: xyz - - Winsock must be initialized before using: - - WSADATA info; - if (WSAStartup(MAKEWORD(1,1), &info) != 0){ - fossil_panic("can't initialize winsock"); - } - - Commands status: ---------------------------------------------------------------------- add OK cgi Not tested changes OK checkout BAD #1 clean OK -clone Local Only #2 +clone OK close OK -commit OK (not tested with gpg signing yet) +commit OK config OK deconstruct OK del OK descendents OK diff OK @@ -54,18 +41,18 @@ leaves OK ls OK merge OK new OK open OK -pull BAD #2 -push BAD #2 +pull OK +push OK rebuild OK (didn't have a corrupt file to try on though) redo BAD #3 rm OK -server BAD #2,#4 +server BAD #4 status OK -sync BAD #2 +sync OK timeline OK tkdiff OK undo OK update OK user capabilities OK @@ -81,12 +68,10 @@ Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and the file appears. Is that normal operation? - -#2 No socket operations are functioning yet #3 In test1/ I edited a file, test2/ I updated, type file.txt changes were there. I then did fossil undo file.txt. The changes were gone and fossil status said I had edited file.txt. A fossil redo did not print anything to the screen and the changes for file.txt are not