Overview
SHA1 Hash: | 3c5482959c058d62b032ad5819a738dd418a73cf |
---|---|
Date: | 2007-09-22 19:43:55 |
User: | drh |
Comment: | Merge in the w32 changes. |
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]Added Makefile.w32 version [7035415b04]
@@ -1,1 +1,48 @@ +#!/usr/bin/make +# +#### The toplevel directory of the source tree. Fossil can be built +# in a directory that is separate from the source tree. Just change +# the following to point from the build directory to the src/ folder. +# +SRCDIR = ./src + +#### C Compiler and options for use in building executables that +# will run on the platform that is doing the build. This is used +# to compile code-generator programs as part of the build process. +# See TCC below for the C compiler for building the finished binary. +# +BCC = gcc -g -O2 + +#### The suffix to add to executable files. ".exe" for windows. +# Nothing for unix. +# +E = + +#### C Compile and options for use in building executables that +# will run on the target platform. This is usually the same +# as BCC, unless you are cross-compiling. This C compiler builds +# the finished binary for fossil. The BCC compiler above is used +# for building intermediate code-generator tools. +# +#TCC = gcc -O6 +#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage +#TCC = gcc -g -Os -Wall +TCC = gcc -g -Os -Wall -DFOSSIL_I18N=0 + +#### Extra arguments for linking the finished binary. Fossil needs +# to link against the Z-Lib compression library. There are no +# 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 -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/add.c from [771768ca0d] to [7e200015f8].
@@ -50,11 +50,11 @@ char *zName; char *zPath; Blob pathname; int isDir; - zName = mprintf("%s", g.argv[i]); + zName = mprintf("%/", g.argv[i]); isDir = file_isdir(zName); if( isDir==1 ) continue; if( isDir==0 ){ fossil_fatal("not found: %s", zName); } @@ -100,11 +100,11 @@ for(i=2; i<g.argc; i++){ char *zName; char *zPath; Blob pathname; - zName = mprintf("%s", g.argv[i]); + zName = mprintf("%/", g.argv[i]); file_tree_name(zName, &pathname); zPath = blob_str(&pathname); if( !db_exists( "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){ fossil_fatal("not in the repository: %s", zName);
Modified src/blob.c from [f2c016552c] to [70f1a3c914].
@@ -571,13 +571,24 @@ } nName = file_simplify_name(zName, nName); for(i=1; i<nName; i++){ if( zName[i]=='/' ){ zName[i] = 0; - if( file_mkdir(zName, 1) ){ - fossil_panic("unable to create directory %s", zName); +#ifdef __MINGW32__ + /* + ** On Windows, local path looks like: C:/develop/project/file.txt + ** The if stops us from trying to create a directory of a drive letter + ** C: in this example. + */ + if( !(i==2 && zName[1]==':') ){ +#endif + if( file_mkdir(zName, 1) ){ + fossil_panic("unable to create directory %s", zName); + } +#ifdef __MINGW32__ } +#endif zName[i] = '/'; } } out = fopen(zName, "wb"); if( out==0 ){
Modified src/cgi.c from [f25a72aeb6] to [57f4d7daa3].
@@ -26,20 +26,26 @@ ** dispensing QUERY_STRING parameters and cookies, the "mprintf()" ** formatting function and its cousins, and routines to encode and ** decode strings in HTML or HTTP. */ #include "config.h" -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <time.h> -#include <sys/times.h> -#include <sys/time.h> -#include <sys/wait.h> +#ifdef __MINGW32__ +# include <windows.h> /* for Sleep once server works again */ +# 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> +# include <sys/times.h> +# include <sys/time.h> +# include <sys/wait.h> +# include <sys/select.h> +#endif +#include <time.h> #include <stdio.h> #include <stdlib.h> -#include <sys/select.h> #include <unistd.h> #include "cgi.h" #if INTERFACE /* @@ -1076,10 +1082,14 @@ ** As new connections arrive, fork a child and let child return ** out of this procedure call. The child will handle the request. ** The parent never returns from this procedure. */ void cgi_http_server(int iPort){ +#ifdef __MINGW32__ + fprintf(stderr,"server not yet available in windows version of fossil\n"); + exit(1); +#else int listener; /* The server socket */ int connection; /* A socket for each individual connection */ fd_set readfds; /* Set of file descriptors for select() */ size_t lenaddr; /* Length of the inaddr structure */ int child; /* PID of the child process */ @@ -1142,10 +1152,11 @@ nchildren--; } } /* NOT REACHED */ exit(1); +#endif } /* ** Name of days and months. */
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/db.c from [16bbdf5494] to [b9655281e8].
@@ -33,14 +33,16 @@ ** (3) A local checkout database named "FOSSIL" and located at the ** root of the local copy of the source tree. ** */ #include "config.h" +#ifndef __MINGW32__ +# include <pwd.h> +#endif #include <sqlite3.h> #include <sys/types.h> #include <sys/stat.h> -#include <pwd.h> #include <unistd.h> #include "db.h" #if INTERFACE /* @@ -488,15 +490,31 @@ ** Open the user database in "~/.fossil". Create the database anew if ** it does not already exist. */ void db_open_config(void){ char *zDbName; - const char *zHome = getenv("HOME"); + const char *zHome; +#ifdef __MINGW32__ + zHome = getenv("LOCALAPPDATA"); + if( zHome==0 ){ + zHome = getenv("APPDATA"); + if( zHome==0 ){ + zHome = getenv("HOMEPATH"); + } + } +#else + zHome = getenv("HOME"); +#endif if( zHome==0 ){ db_err("cannot local home directory"); } +#ifdef __MINGW32__ + /* . filenames give some window systems problems and many apps problems */ + zDbName = mprintf("%s/_fossil", zHome); +#else zDbName = mprintf("%s/.fossil", zHome); +#endif if( g.configOpen ) return; if( file_size(zDbName)<1024*3 ){ db_init_database(zDbName, zConfigSchema, (char*)0); } db_open_or_attach(zDbName, "configdb"); @@ -534,15 +552,19 @@ ** it is attached to the open database connection too. */ int db_open_local(void){ int n; char zPwd[2000]; + char *zPwdConv; if( g.localOpen) return 1; if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ db_err("pwd too big: max %d", sizeof(zPwd)-20); } n = strlen(zPwd); + zPwdConv = mprintf("%/", zPwd); + strncpy(zPwd, zPwdConv, 2000-20); + free(zPwdConv); while( n>0 ){ if( access(zPwd, W_OK) ) break; strcpy(&zPwd[n], "/_FOSSIL_"); if( isValidLocalDb(zPwd) ){ /* Found a valid _FOSSIL_ file */
Modified src/file.c from [43aa6bdf65] to [0453cec099].
@@ -105,11 +105,15 @@ if( rc==2 ){ if( !forceFlag ) return 1; unlink(zName); } if( rc!=1 ){ +#ifdef __MINGW32__ + return mkdir(zName); +#else return mkdir(zName, 0755); +#endif } return 0; } /* @@ -188,11 +192,11 @@ if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ fprintf(stderr, "pwd too big: max %d\n", sizeof(zPwd)-20); exit(1); } blob_zero(pOut); - blob_appendf(pOut, "%s/%s", zPwd, zOrigName); + blob_appendf(pOut, "%//%/", zPwd, zOrigName); } blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut))); } /*
Modified src/http.c from [43986095c4] to [54410d4f2b].
@@ -23,22 +23,55 @@ ** ** This file contains code that implements the client-side HTTP protocol */ #include "config.h" #include "http.h" +#ifdef __MINGW32__ +# include <windows.h> +# include <winsock2.h> +#else +# include <arpa/inet.h> +# include <sys/socket.h> +# include <netdb.h> +# include <netinet/in.h> +#endif #include <assert.h> -#include <arpa/inet.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> +#include <sys/types.h> #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(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 +} /* ** Open a socket connection to the server. Return 0 on success and ** non-zero if an error occurs. */ @@ -45,11 +78,14 @@ 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; + 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 ){ #ifndef FOSSIL_STATIC_LINK @@ -76,13 +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); } +#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. @@ -93,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 */ @@ -135,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 ){ @@ -260,9 +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); +#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 src/login.c from [4e89d2580b] to [d1ac22275c].
@@ -44,10 +44,14 @@ ** logs and downloading diffs of very version of the archive that ** has ever existed, and things like that. */ #include "config.h" #include "login.h" +#ifdef __MINGW32__ +# include <windows.h> /* for Sleep */ +# define sleep Sleep /* windows does not have sleep, but Sleep */ +#endif #include <time.h> /* ** Return the name of the login cookie */
Modified src/printf.c from [48f1118d8e] to [63619c9ec6].
@@ -49,10 +49,11 @@ #define etPOINTER 15 /* The %p conversion */ #define etHTMLIZE 16 /* Make text safe for HTML */ #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */ #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */ #define etFOSSILIZE 19 /* The fossil header encoding format. */ +#define etPATH 20 /* Path type */ /* ** An "etByte" is an 8-bit unsigned value. */ @@ -109,10 +110,11 @@ { 'G', 0, 1, etGENERIC, 14, 0 }, { 'i', 10, 1, etRADIX, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, + { '/', 0, 0, etPATH, 0, 0 }, }; #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) /* ** "*val" is a double such that 0.1 <= *val < 10.0 @@ -541,10 +543,26 @@ }else{ length =1; } bufpt = buf; break; + case etPATH: { + int i; + char *e = va_arg(ap,char*); + if( e==0 ){e="";} + length = strlen(e); + zExtra = bufpt = malloc(length+1); + for( i=0; i<length; i++ ){ + if( e[i]=='\\' ){ + bufpt[i]='/'; + }else{ + bufpt[i]=e[i]; + } + } + bufpt[length]='\0'; + break; + } case etSTRING: case etDYNSTRING: bufpt = va_arg(ap,char*); if( bufpt==0 ){ bufpt = "";
Modified src/user.c from [7f6b214713] to [2a5d91addf].
@@ -44,10 +44,50 @@ } if( z[i]<' ' ) z[i] = ' '; } blob_append(pBlob, z, -1); } + +#ifdef __MINGW32__ +/* +** getpass for Windows +*/ +static char *getpass(const char *prompt){ + static char pwd[64]; + size_t i; + + fputs(prompt,stderr); + fflush(stderr); + for(i=0; i<sizeof(pwd)-1; ++i){ + pwd[i] = _getch(); + if(pwd[i]=='\r' || pwd[i]=='\n'){ + break; + } + /* BS or DEL */ + else if(i>0 && (pwd[i]==8 || pwd[i]==127)){ + i -= 2; + continue; + } + /* CTRL-C */ + else if(pwd[i]==3) { + i=0; + break; + } + /* ESC */ + else if(pwd[i]==27){ + i=0; + break; + } + else{ + fputc('*',stderr); + } + } + pwd[i]='\0'; + fputs("\n", stderr); + return pwd; +} +#endif /* ** Do a single prompt for a passphrase. Store the results in the blob. */ static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){
Added win32.txt version [f8b38cdb44]
@@ -1,1 +1,84 @@ +Notes: Porting fossil to win32 +====================================================================== + +Setting up my build environment: +---------------------------------------------------------------------- + + Install: + MinGW 5.1.3 + MSYS 1.0.10 + + 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 + +Commands status: +---------------------------------------------------------------------- + +add OK +cgi Not tested +changes OK +checkout BAD #1 +clean OK +clone OK +close OK +commit OK +config OK +deconstruct OK +del OK +descendents OK +diff OK +extra OK +help OK +http Not Tested +info OK +leaves OK +ls OK +merge OK +new OK +open OK +pull OK +push OK +rebuild OK (didn't have a corrupt file to try on though) +redo BAD #3 +rm OK +server BAD #4 +status OK +sync OK +timeline OK +tkdiff OK +undo OK +update OK +user capabilities OK +user default OK +user list OK +user new OK +user password OK + +#1 Have a repo where I removed a file. I did a fossil checkout 123abc, + which is the last version that had the file. The file does not + appear. fossil checkout --force 123abc does things, but still the + file does not appear. + + Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and + the file appears. + + Is that normal operation? + +#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 + in the file. fossil status still reports that the file was edited. + There was no commit/update or any other command inbetween these + actions. +#4 There were various difficulties in this function beyond simple socket + problems. The major one being fork. This will probably be the last + command to be functional in fossil on windows.