Fossil

Check-in [0cdb6403]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The ssh:// method on windows is now working well with plink. It will even prompt for passwords if the URL contains a "*" password.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:0cdb6403cb1dd73dee52dfc2c6c556be657acf5a
User & Date: drh 2010-08-27 20:40:57
Context
2010-08-28
19:04
Use -P to change ssh port numbers on windows, but -p on unix. check-in: 1212f0b0 user: drh tags: trunk
2010-08-27
20:40
The ssh:// method on windows is now working well with plink. It will even prompt for passwords if the URL contains a "*" password. check-in: 0cdb6403 user: drh tags: trunk
17:19
Fix a typo in the popen2() implementation for windows. Ticket [cf50ea4d6914fb6d856988da7]. Also refinements on the ssh:// toward getting it working on windows. check-in: d5c934e5 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/blob.c.

894
895
896
897
898
899
900





















  z = p->aData;
  for(i=j=0; z[i]; i++){
    if( z[i]!='\r' ) z[j++] = z[i];
  }
  z[j] = 0;
  p->nUsed = j;
}




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
  z = p->aData;
  for(i=j=0; z[i]; i++){
    if( z[i]!='\r' ) z[j++] = z[i];
  }
  z[j] = 0;
  p->nUsed = j;
}

/*
** Shell-escape the given string.  Append the result to a blob.
*/
void shell_escape(Blob *pBlob, const char *zIn){
  int n = blob_size(pBlob);
  int k = strlen(zIn);
  int i, c;
  char *z;
  for(i=0; (c = zIn[i])!=0; i++){
    if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
      blob_appendf(pBlob, "\"%s\"", zIn);
      z = blob_buffer(pBlob);
      for(i=n+1; i<=n+k; i++){
        if( z[i]=='"' ) z[i] = '_';
      }
      return;
    }
  }
  blob_append(pBlob, zIn, -1);
}

Changes to src/db.c.

1552
1553
1554
1555
1556
1557
1558



1559
1560
1561
1562
1563
1564
1565
....
1575
1576
1577
1578
1579
1580
1581

1582
1583
1584
1585
1586
1587
1588
**    pgp-command      Command used to clear-sign manifests at check-in.
**                     The default is "gpg --clearsign -o ".
**
**    proxy            URL of the HTTP proxy.  If undefined or "off" then
**                     the "http_proxy" environment variable is consulted.
**                     If the http_proxy environment variable is undefined
**                     then a direct HTTP connection is used.



**
**    web-browser      A shell command used to launch your preferred
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,
**                     and "firefox" on Unix.
*/
void setting_cmd(void){
................................................................................
    "gdiff-command",
    "ignore-glob",
    "http-port",
    "localauth",
    "mtime-changes",
    "pgp-command",
    "proxy",

    "web-browser",
  };
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  db_open_config(1);
  db_find_and_open_repository(0);







>
>
>







 







>







1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
....
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
**    pgp-command      Command used to clear-sign manifests at check-in.
**                     The default is "gpg --clearsign -o ".
**
**    proxy            URL of the HTTP proxy.  If undefined or "off" then
**                     the "http_proxy" environment variable is consulted.
**                     If the http_proxy environment variable is undefined
**                     then a direct HTTP connection is used.
**
**    ssh-command      Command used to talk to a remote machine with
**                     the "ssh://" protocol.
**
**    web-browser      A shell command used to launch your preferred
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,
**                     and "firefox" on Unix.
*/
void setting_cmd(void){
................................................................................
    "gdiff-command",
    "ignore-glob",
    "http-port",
    "localauth",
    "mtime-changes",
    "pgp-command",
    "proxy",
    "ssh-command",
    "web-browser",
  };
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  db_open_config(1);
  db_find_and_open_repository(0);

Changes to src/diffcmd.c.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>

/*
** Shell-escape the given string.  Append the result to a blob.
*/
void shell_escape(Blob *pBlob, const char *zIn){
  int n = blob_size(pBlob);
  int k = strlen(zIn);
  int i, c;
  char *z;
  for(i=0; (c = zIn[i])!=0; i++){
    if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
      blob_appendf(pBlob, "\"%s\"", zIn);
      z = blob_buffer(pBlob);
      for(i=n+1; i<=n+k; i++){
        if( z[i]=='"' ) z[i] = '_';
      }
      return;
    }
  }
  blob_append(pBlob, zIn, -1);
}

/*
** This function implements a cross-platform "system()" interface.
*/
int portable_system(const char *zOrigCmd){
  int rc;
#ifdef __MINGW32__
  /* On windows, we have to put double-quotes around the entire command.







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







17
18
19
20
21
22
23





















24
25
26
27
28
29
30
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>






















/*
** This function implements a cross-platform "system()" interface.
*/
int portable_system(const char *zOrigCmd){
  int rc;
#ifdef __MINGW32__
  /* On windows, we have to put double-quotes around the entire command.

Changes to src/http_transport.c.

86
87
88
89
90
91
92









93
94
95
96
97















98
99









100
101






102
103
104
105
106
107
108
109



110
111
112
113
114
115




116
117
118
119

120
121
122
123
124
125
126
127
  while( got>=0 ){
    zBuf[got] = 0;
    if( got==0 || !isspace(zBuf[got-1]) ) break;
    got--;
  }
}










/*
** Global initialization of the transport layer
*/
void transport_global_startup(void){
  if( g.urlIsSsh ){















#ifdef __MINGW32__
    static const char *zSshCmd = "ssh";









#else
    static const char *zSshCmd = "ssh -e none";






#endif
    char *zCmd;
    char zIn[20];
    if( g.urlUser && g.urlUser[0] ){
      zCmd = mprintf("%s %s@%s", zSshCmd, g.urlUser, g.urlName);
    }else{
      zCmd = mprintf("%s %s", zSshCmd, g.urlName);
    }



    /* printf("%s\n", zCmd); */
    popen2(zCmd, &sshIn, &sshOut, &sshPid);
    if( sshPid==0 ){
      fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
    }
    free(zCmd);




    fprintf(sshOut, "echo test\n");
    fflush(sshOut);
    sshin_read(zIn, sizeof(zIn));
    if( memcmp(zIn, "test", 4)!=0 ){

      fossil_fatal("ssh connection failed");
    }
  }
}

/*
** Open a connection to the server.  The server is defined by the following
** global variables:







>
>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>

<
<
<
<

|

>
>
>
|
|

|

|
>
>
>
>




>
|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139




140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  while( got>=0 ){
    zBuf[got] = 0;
    if( got==0 || !isspace(zBuf[got-1]) ) break;
    got--;
  }
}

/*
** Default SSH command
*/
#ifdef __MINGW32__
static char zDefaultSshCmd[] = "ssh -T";
#else
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif

/*
** Global initialization of the transport layer
*/
void transport_global_startup(void){
  if( g.urlIsSsh ){
    /* Only SSH requires a global initialization.  For SSH we need to create
    ** and run an SSH command to talk to the remote machine.
    */
    const char *zSsh;  /* The base SSH command */
    Blob zCmd;         /* The SSH command */
    char *zHost;       /* The host name to contact */
    char zIn[200];     /* An input line received back from remote */

    zSsh = db_get("ssh-command", zDefaultSshCmd);
    blob_init(&zCmd, zSsh, -1);
    if( g.urlPort!=g.urlDfltPort ){
      blob_appendf(&zCmd, " -P %d", g.urlPort);
    }
    if( g.urlUser && g.urlUser[0] ){
      zHost = mprintf("%s@%s", g.urlUser, g.urlName);
#ifdef __MINGW32__

      /* Only win32 (and specifically PLINK.EXE support the -pw option */
      if( g.urlPasswd && g.urlPasswd[0] ){
        Blob pw;
        blob_zero(&pw);
        if( g.urlPasswd[0]=='*' ){
          char *zPrompt;
          zPrompt = mprintf("Password for [%s]: ", zHost);
          prompt_for_password(zPrompt, &pw, 0);
          free(zPrompt);
        }else{

          blob_init(&pw, g.urlPasswd, -1);
        }
        blob_append(&zCmd, " -pw ", -1);
        shell_escape(&zCmd, blob_str(&pw));
        blob_reset(&pw);
      }
#endif




    }else{
      zHost = mprintf("%s", g.urlName);
    }
    blob_append(&zCmd, " ", 1);
    shell_escape(&zCmd, zHost);
    free(zHost);
    /* printf("%s\n", blob_str(&zCmd)); */
    popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
    if( sshPid==0 ){
      fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
    }
    blob_reset(&zCmd);

    /* Send an "echo" command to the other side to make sure that the
    ** connection is up and working.
    */
    fprintf(sshOut, "echo test\n");
    fflush(sshOut);
    sshin_read(zIn, sizeof(zIn));
    if( memcmp(zIn, "test", 4)!=0 ){
      pclose2(sshIn, sshOut, sshPid);
      fossil_fatal("ssh connection failed: [%s]", zIn);
    }
  }
}

/*
** Open a connection to the server.  The server is defined by the following
** global variables:

Changes to src/popen.c.

171
172
173
174
175
176
177


178
179
180
181
182
183
/*
** Close the connection to a child process previously created using
** popen2().  Kill off the child process, then close the pipes.
*/
void pclose2(int fdIn, FILE *pOut, int childPid){
#ifdef __MINGW32__
  /* Not implemented, yet */


#else
  close(fdIn);
  fclose(pOut);
  kill(childPid, SIGINT);
#endif
}







>
>






171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
** Close the connection to a child process previously created using
** popen2().  Kill off the child process, then close the pipes.
*/
void pclose2(int fdIn, FILE *pOut, int childPid){
#ifdef __MINGW32__
  /* Not implemented, yet */
  close(fdIn);
  fclose(pOut);
#else
  close(fdIn);
  fclose(pOut);
  kill(childPid, SIGINT);
#endif
}

Changes to src/url.c.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61



62
63


64
65
66
67
68
69






70
71
72
73
74
75
76
..
81
82
83
84
85
86
87



88

89
90
91
92
93
94
95
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

152
153
154
155
156
157
158
...
172
173
174
175
176
177
178

179

180
181
182
183






184
185
186
187
188
189
190
191
192
**      g.urlUser        Userid.
**      g.urlPasswd      Password.
**      g.urlHostname    HOST:PORT or just HOST if port is the default.
**      g.urlCanonical   The URL in canonical form, omitting the password
**
** HTTP url format is:
**
**     http://userid:password@host:port/path?query#fragment
**
** SSH url format is:
**
**     ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl){
  int i, j, c;
  char *zFile = 0;
  if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){



    int iStart;
    char *zLogin;


    g.urlIsFile = 0;
    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;






    }else{
      g.urlIsHttps = 0;
      g.urlProtocol = "http";
      g.urlDfltPort = 80;
      iStart = 7;
    }
    for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
................................................................................
      if( j<i ){
        g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
        dehttpize(g.urlPasswd);
      }
      for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
      g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
      i = j;



      zLogin = mprintf("%t@", g.urlUser);

    }else{
      g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
      zLogin = mprintf("");
    }
    url_tolower(g.urlName);
    if( c==':' ){
      g.urlPort = 0;
................................................................................
        i++;
      }
      g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
    }else{
      g.urlPort = g.urlDfltPort;
      g.urlHostname = g.urlName;
    }
    g.urlPath = mprintf(&zUrl[i]);
    dehttpize(g.urlName);
    dehttpize(g.urlPath);
    if( g.urlDfltPort==g.urlPort ){
      g.urlCanonical = mprintf(
        "%s://%s%T%T", 
        g.urlProtocol, zLogin, g.urlName, g.urlPath
      );
    }else{
      g.urlCanonical = mprintf(
        "%s://%s%T:%d%T",
        g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
      );
    }
    free(zLogin);
  }else if( strncmp(zUrl, "ssh://", 6)==0 ){
    char *zLogin;
    char *zExe;
    int i, j;
    g.urlIsFile = 0;
    g.urlIsSsh = 1;
    g.urlProtocol = "ssh";
    g.urlPort = 22;
    g.urlDfltPort = 22;
    g.urlPasswd = "(not-used)";
    g.urlFossil = "fossil";
    for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
    if( c=='@' ){
      for(j=6; j<i && zUrl[j]!=':'; j++){}
      g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
      dehttpize(g.urlUser);
      if( j<i ){
        g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
        dehttpize(g.urlPasswd);
      }
      for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
      g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
      i = j;
      zLogin = mprintf("%t@", g.urlUser);
    }else{
      g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
      zLogin = mprintf("");
    }
    url_tolower(g.urlName);
    g.urlHostname = g.urlName;
    g.urlPath = mprintf(&zUrl[i+1]);

    for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
    if( g.urlPath[i] ){
      g.urlPath[i] = 0;
      i++;
    }
    zExe = mprintf("");
    while( g.urlPath[i]!=0 ){
................................................................................
      }
      if( strcmp(zName,"fossil")==0 ){
        g.urlFossil = zValue;
        dehttpize(g.urlFossil);
        zExe = mprintf("?fossil=%T", g.urlFossil);
      }
    }

    dehttpize(g.urlPath);

    g.urlCanonical = mprintf(
        "ssh://%s%T/%T%s", 
        zLogin, g.urlName, g.urlPath, zExe
    );






    free(zLogin);
    free(zExe);
  }else if( strncmp(zUrl, "file:", 5)==0 ){
    g.urlIsFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }







|



|





|
>
>
>


>
>






>
>
>
>
>
>







 







>
>
>
|
>







 







<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>







 







>

>
|
|
|
|
>
>
>
>
>
>

<







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
...
114
115
116
117
118
119
120

121











































122
123
124
125
126
127
128
129
130
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
**      g.urlUser        Userid.
**      g.urlPasswd      Password.
**      g.urlHostname    HOST:PORT or just HOST if port is the default.
**      g.urlCanonical   The URL in canonical form, omitting the password
**
** HTTP url format is:
**
**     http://userid:password@host:port/path
**
** SSH url format is:
**
**     ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl){
  int i, j, c;
  char *zFile = 0;
  if( strncmp(zUrl, "http://", 7)==0
   || strncmp(zUrl, "https://", 8)==0
   || strncmp(zUrl, "ssh://", 6)==0
  ){
    int iStart;
    char *zLogin;
    char *zExe;

    g.urlIsFile = 0;
    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;
    }else if( zUrl[0]=='s' ){
      g.urlIsSsh = 1;
      g.urlProtocol = "ssh";
      g.urlDfltPort = 22;
      g.urlFossil = "fossil";
      iStart = 6;
    }else{
      g.urlIsHttps = 0;
      g.urlProtocol = "http";
      g.urlDfltPort = 80;
      iStart = 7;
    }
    for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
................................................................................
      if( j<i ){
        g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
        dehttpize(g.urlPasswd);
      }
      for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
      g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
      i = j;
      if( g.urlIsSsh && g.urlPasswd ){
        zLogin = mprintf("%t:*@", g.urlUser);
      }else{
        zLogin = mprintf("%t@", g.urlUser);
      }
    }else{
      g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
      zLogin = mprintf("");
    }
    url_tolower(g.urlName);
    if( c==':' ){
      g.urlPort = 0;
................................................................................
        i++;
      }
      g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
    }else{
      g.urlPort = g.urlDfltPort;
      g.urlHostname = g.urlName;
    }

    dehttpize(g.urlName);











































    g.urlPath = mprintf(&zUrl[i]);
    if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
    for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
    if( g.urlPath[i] ){
      g.urlPath[i] = 0;
      i++;
    }
    zExe = mprintf("");
    while( g.urlPath[i]!=0 ){
................................................................................
      }
      if( strcmp(zName,"fossil")==0 ){
        g.urlFossil = zValue;
        dehttpize(g.urlFossil);
        zExe = mprintf("?fossil=%T", g.urlFossil);
      }
    }

    dehttpize(g.urlPath);
    if( g.urlDfltPort==g.urlPort ){
      g.urlCanonical = mprintf(
        "%s://%s%T%T%s", 
        g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
      );
    }else{
      g.urlCanonical = mprintf(
        "%s://%s%T:%d%T%s",
        g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
      );
    }
    free(zLogin);

  }else if( strncmp(zUrl, "file:", 5)==0 ){
    g.urlIsFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }