Index: Makefile.in
==================================================================
--- Makefile.in
+++ Makefile.in
@@ -43,10 +43,11 @@
BCCFLAGS = @CPPFLAGS@ @CFLAGS@
TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H
INSTALLDIR = $(DESTDIR)@prefix@/bin
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
USE_LINENOISE = @USE_LINENOISE@
+USE_MMAN_H = @USE_MMAN_H@
USE_SEE = @USE_SEE@
FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@
include $(SRCDIR)/main.mk
ADDED Makefile.osx-jaguar
Index: Makefile.osx-jaguar
==================================================================
--- /dev/null
+++ Makefile.osx-jaguar
@@ -0,0 +1,70 @@
+#!/usr/bin/make
+#
+# This is a specially modified version of the Makefile that will build
+# Fossil on Mac OSX Jaguar (10.2) circa 2002. This Makefile is used for
+# testing on an old PPC iBook. The use of this old platform helps to verify
+# Fossil and SQLite running on big-endian hardware.
+#
+# To build with this Makefile, run:
+#
+# make -f Makefile.osx-jaguar
+#
+#
+# This is the top-level makefile for Fossil when the build is occurring
+# on a unix platform. This works out-of-the-box on most unix platforms.
+# But you are free to vary some of the definitions if desired.
+#
+#### 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
+
+#### The directory into which object code files should be written.
+# Having a "./" prefix in the value of this variable breaks our use of the
+# "makeheaders" tool when running make on the MinGW platform, apparently
+# due to some command line argument manipulation performed automatically
+# by the shell.
+#
+#
+OBJDIR = bld
+
+#### 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 = cc
+
+#### The suffix to add to final executable file. When cross-compiling
+# to windows, make this ".exe". Otherwise leave it blank.
+#
+E =
+
+TCC = cc
+
+#### Tcl shell for use in running the fossil testsuite. If you do not
+# care about testing the end result, this can be blank.
+#
+TCLSH = tclsh
+
+# LIB = -lz
+LIB = compat/zlib/libz.a
+TCC += -g -O0 -DHAVE_AUTOCONFIG_H
+TCC += -Icompat/zlib
+TCC += -DSQLITE_WITHOUT_ZONEMALLOC
+TCC += -D_BSD_SOURCE=1
+TCC += -DWITHOUT_ICONV
+TCC += -Dsocklen_t=int
+TCC += -DSQLITE_MAX_MMAP_SIZE=0
+INSTALLDIR = $(DESTDIR)/usr/local/bin
+USE_SYSTEM_SQLITE =
+USE_LINENOISE = 1
+# FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
+FOSSIL_ENABLE_TCL = 0
+FOSSIL_ENABLE_MINIZ = 0
+
+include $(SRCDIR)/main.mk
+
+distclean: clean
+ rm -f autoconfig.h config.log Makefile
Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
-2.5
+2.6
Index: auto.def
==================================================================
--- auto.def
+++ auto.def
@@ -15,10 +15,11 @@
with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages}
with-tcl:path => {Enable Tcl integration, with Tcl in the specified path}
with-tcl-stubs=0 => {Enable Tcl integration via stubs library mechanism}
with-tcl-private-stubs=0
=> {Enable Tcl integration via private stubs mechanism}
+ with-mman=0 => {Enable use of POSIX memory APIs from "sys/mman.h"}
with-see=0 => {Enable the SQLite Encryption Extension (SEE)}
internal-sqlite=1 => {Don't use the internal SQLite, use the system one}
static=0 => {Link a static executable}
fusefs=1 => {Disable the Fuse Filesystem}
fossil-debug=0 => {Build with fossil debugging enabled}
@@ -40,10 +41,11 @@
define EXTRA_CFLAGS "-Wall"
define EXTRA_LDFLAGS ""
define USE_SYSTEM_SQLITE 0
define USE_LINENOISE 0
define FOSSIL_ENABLE_MINIZ 0
+define USE_MMAN_H 0
define USE_SEE 0
# This procedure is a customized version of "cc-check-function-in-lib",
# that does not modify the LIBS variable. Its use prevents prematurely
# pulling in libraries that will be added later anyhow (e.g. "-ldl").
@@ -89,17 +91,17 @@
# the code below will append -ldl to LIBS.
#
foreach extralibs {{} {-ldl}} {
# Locate the system SQLite by searching for sqlite3_open(). Then check
- # if sqlite3_vtab_collation() can be found as well. If we can find open() but
- # not vtab_collation(), then the system SQLite is too old to link against
+ # if sqlite3_keyword_check() can be found as well. If we can find open() but
+ # not keyword_check(), then the system SQLite is too old to link against
# fossil.
#
if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
- if {![check-function-in-lib sqlite3_vtab_collation sqlite3 $extralibs]} {
- user-error "system sqlite3 too old (require >= 3.22.0)"
+ if {![check-function-in-lib sqlite3_keyword_check sqlite3 $extralibs]} {
+ user-error "system sqlite3 too old (require >= 3.24.0)"
}
# Success. Update symbols and return.
#
define USE_SYSTEM_SQLITE 1
@@ -141,10 +143,16 @@
if {[opt-bool no-opt]} {
define CFLAGS {-g -O0 -Wall}
msg-result "Builting without compiler optimization"
}
+
+if {[opt-bool with-mman]} {
+ define-append EXTRA_CFLAGS -DUSE_MMAN_H
+ define USE_MMAN_H 1
+ msg-result "Enabling \"sys/mman.h\" support"
+}
if {[opt-bool with-see]} {
define-append EXTRA_CFLAGS -DUSE_SEE
define USE_SEE 1
msg-result "Enabling encryption support"
Index: src/add.c
==================================================================
--- src/add.c
+++ src/add.c
@@ -859,10 +859,12 @@
int vid;
int moveFiles;
int dryRunFlag;
int softFlag;
int hardFlag;
+ int origType;
+ int destType;
char *zDest;
Blob dest;
Stmt q;
db_must_be_within_tree();
@@ -900,15 +902,23 @@
"UPDATE vfile SET origname=pathname WHERE origname IS NULL;"
);
db_multi_exec(
"CREATE TEMP TABLE mv(f TEXT UNIQUE ON CONFLICT IGNORE, t TEXT);"
);
- if( file_isdir(zDest, RepoFILE)!=1 ){
+ if( g.argc!=4 ){
+ origType = -1;
+ }else{
+ origType = (file_isdir(g.argv[2], RepoFILE) == 1);
+ }
+ destType = file_isdir(zDest, RepoFILE);
+ if( origType==-1 && destType!=1 ){
+ usage("OLDNAME NEWNAME");
+ }else if( origType==1 && destType==2 ){
+ fossil_fatal("cannot rename '%s' to '%s' since another file named"
+ " '%s' exists", g.argv[2], zDest, zDest);
+ }else if( origType==0 && destType!=1 ){
Blob orig;
- if( g.argc!=4 ){
- usage("OLDNAME NEWNAME");
- }
file_tree_name(g.argv[2], &orig, 0, 1);
db_multi_exec(
"INSERT INTO mv VALUES(%B,%B)", &orig, &dest
);
}else{
@@ -936,10 +946,12 @@
const char *zPath = db_column_text(&q, 0);
int nPath = db_column_bytes(&q, 0);
const char *zTail;
if( nPath==nOrig ){
zTail = file_tail(zPath);
+ }else if( destType==1 ){
+ zTail = &zPath[nOrig-strlen(file_tail(zOrig))];
}else{
zTail = &zPath[nOrig+1];
}
db_multi_exec(
"INSERT INTO mv VALUES('%q','%q%q')",
Index: src/blob.c
==================================================================
--- src/blob.c
+++ src/blob.c
@@ -114,10 +114,18 @@
return (c>='a' && c<='z') || (c>='A' && c<='Z');
}
int fossil_isalnum(char c){
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
}
+
+/* Return true if and only if the entire string consists of only
+** alphanumeric characters.
+*/
+int fossil_no_strange_characters(const char *z){
+ while( z && (fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-') ) z++;
+ return z[0]==0;
+}
/*
** COMMAND: test-isspace
**
Index: src/cache.c
==================================================================
--- src/cache.c
+++ src/cache.c
@@ -165,17 +165,25 @@
sqlite3_bind_int(pStmt, 3, sqlite3_last_insert_rowid(db));
if( sqlite3_step(pStmt)!=SQLITE_DONE) goto cache_write_end;
rc = sqlite3_changes(db);
/* If the write was successful, truncate the cache to keep at most
- ** max-cache-entry entries in the cache */
+ ** max-cache-entry entries in the cache.
+ **
+ ** The cache entry replacement algorithm is approximately LRU
+ ** (least recently used). However, each access of an entry buys
+ ** that entry an extra hour of grace, so that more commonly accessed
+ ** entries are held in cache longer. The extra "grace" allotted to
+ ** an entry is limited to 2 days worth.
+ */
if( rc ){
nKeep = db_get_int("max-cache-entry",10);
sqlite3_finalize(pStmt);
pStmt = cacheStmt(db,
"DELETE FROM cache WHERE rowid IN ("
- "SELECT rowid FROM cache ORDER BY tm DESC"
+ "SELECT rowid FROM cache"
+ " ORDER BY (tm + 3600*min(nRef,48)) DESC"
" LIMIT -1 OFFSET ?1)");
if( pStmt ){
sqlite3_bind_int(pStmt, 1, nKeep);
sqlite3_step(pStmt);
}
@@ -291,11 +299,12 @@
sqlite3_close(db);
fossil_print("cache cleared\n");
}else{
fossil_print("nothing to clear; cache does not exist\n");
}
- }else if(( strncmp(zCmd, "list", nCmd)==0 ) || ( strncmp(zCmd, "ls", nCmd)==0 )){
+ }else if(( strncmp(zCmd, "list", nCmd)==0 )
+ || ( strncmp(zCmd, "ls", nCmd)==0 )){
db = cacheOpen(0);
if( db==0 ){
fossil_print("cache does not exist\n");
}else{
int nEntry = 0;
@@ -350,11 +359,11 @@
char *zDbName = cacheName();
cache_register_sizename(db);
pStmt = cacheStmt(db,
"SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')"
" FROM cache"
- " ORDER BY tm DESC"
+ " ORDER BY (tm + 3600*min(nRef,48)) DESC"
);
if( pStmt ){
@
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const unsigned char *zName = sqlite3_column_text(pStmt,0);
Index: src/cgi.c
==================================================================
--- src/cgi.c
+++ src/cgi.c
@@ -217,73 +217,20 @@
}
if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){
zSecure = " secure;";
}
if( lifetime>0 ){
- lifetime += (int)time(0);
blob_appendf(&extraHeader,
- "Set-Cookie: %s=%t; Path=%s; expires=%z; HttpOnly;%s Version=1\r\n",
- zName, zValue, zPath, cgi_rfc822_datestamp(lifetime), zSecure);
+ "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly;%s Version=1\r\n",
+ zName, zValue, zPath, lifetime, zSecure);
}else{
blob_appendf(&extraHeader,
"Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n",
zName, zValue, zPath, zSecure);
}
}
-#if 0
-/*
-** Add an ETag header line
-*/
-static char *cgi_add_etag(char *zTxt, int nLen){
- MD5Context ctx;
- unsigned char digest[16];
- int i, j;
- char zETag[64];
-
- MD5Init(&ctx);
- MD5Update(&ctx,zTxt,nLen);
- MD5Final(digest,&ctx);
- for(j=i=0; i<16; i++,j+=2){
- bprintf(&zETag[j],sizeof(zETag)-j,"%02x",(int)digest[i]);
- }
- blob_appendf(&extraHeader, "ETag: %s\r\n", zETag);
- return fossil_strdup(zETag);
-}
-
-/*
-** Do some cache control stuff. First, we generate an ETag and include it in
-** the response headers. Second, we do whatever is necessary to determine if
-** the request was asking about caching and whether we need to send back the
-** response body. If we shouldn't send a body, return non-zero.
-**
-** Currently, we just check the ETag against any If-None-Match header.
-**
-** FIXME: In some cases (attachments, file contents) we could check
-** If-Modified-Since headers and always include Last-Modified in responses.
-*/
-static int check_cache_control(void){
- /* FIXME: there's some gotchas wth cookies and some headers. */
- char *zETag = cgi_add_etag(blob_buffer(&cgiContent),blob_size(&cgiContent));
- char *zMatch = P("HTTP_IF_NONE_MATCH");
-
- if( zETag!=0 && zMatch!=0 ) {
- char *zBuf = fossil_strdup(zMatch);
- if( zBuf!=0 ){
- char *zTok = 0;
- char *zPos;
- for( zTok = strtok_r(zBuf, ",\"",&zPos);
- zTok && fossil_stricmp(zTok,zETag);
- zTok = strtok_r(0, ",\"",&zPos)){}
- fossil_free(zBuf);
- if(zTok) return 1;
- }
- }
-
- return 0;
-}
-#endif
/*
** Return true if the response should be sent with Content-Encoding: gzip.
*/
static int is_gzippable(void){
@@ -301,29 +248,32 @@
if( iReplyStatus<=0 ){
iReplyStatus = 200;
zReplyStatus = "OK";
}
-#if 0
- if( iReplyStatus==200 && check_cache_control() ) {
- /* change the status to "unchanged" and we can skip sending the
- ** actual response body. Obviously we only do this when we _have_ a
- ** body (code 200).
- */
- iReplyStatus = 304;
- zReplyStatus = "Not Modified";
- }
-#endif
-
if( g.fullHttpReply ){
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
fprintf(g.httpOut, "Connection: close\r\n");
fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
}else{
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
+ if( g.isConst ){
+ /* isConst means that the reply is guaranteed to be invariant, even
+ ** after configuration changes and/or Fossil binary recompiles. */
+ fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
+ }else if( etag_tag()!=0 ){
+ fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
+ fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
+ }else{
+ fprintf(g.httpOut, "Cache-control: no-cache\r\n");
+ }
+ if( etag_mtime()>0 ){
+ fprintf(g.httpOut, "Last-Modified: %s\r\n",
+ cgi_rfc822_datestamp(etag_mtime()));
+ }
if( blob_size(&extraHeader)>0 ){
fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
}
@@ -343,24 +293,10 @@
**
** These headers are probably best added by the web server hosting fossil as
** a CGI script.
*/
- if( g.isConst ){
- /* constant means that the input URL will _never_ generate anything
- ** else. In the case of attachments, the contents won't change because
- ** an attempt to change them generates a new attachment number. In the
- ** case of most /getfile calls for specific versions, the only way the
- ** content changes is if someone breaks the SCM. And if that happens, a
- ** stale cache is the least of the problem. So we provide an Expires
- ** header set to a reasonable period (default: one week).
- */
- fprintf(g.httpOut, "Cache-control: max-age=28800\r\n");
- }else{
- fprintf(g.httpOut, "Cache-control: no-cache\r\n");
- }
-
/* Content intended for logged in users should only be cached in
** the browser, not some shared location.
*/
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
@@ -619,10 +555,15 @@
** are ignored.
**
** * it is impossible for a cookie or query parameter to
** override the value of an environment variable since
** environment variables always have uppercase names.
+**
+** 2018-03-29: Also ignore the entry if NAME that contains any characters
+** other than [a-zA-Z0-9_]. There are no known exploits involving unusual
+** names that contain characters outside that set, but it never hurts to
+** be extra cautious when sanitizing inputs.
**
** Parameters are separated by the "terminator" character. Whitespace
** before the NAME is ignored.
**
** The input string "z" is modified but no copies is made. "z"
@@ -649,11 +590,11 @@
dehttpize(zValue);
}else{
if( *z ){ *z++ = 0; }
zValue = "";
}
- if( fossil_islower(zName[0]) ){
+ if( fossil_islower(zName[0]) && fossil_no_strange_characters(zName+1) ){
cgi_set_parameter_nocopy(zName, zValue, isQP);
}
#ifdef FOSSIL_ENABLE_JSON
json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
#endif /* FOSSIL_ENABLE_JSON */
@@ -1977,55 +1918,42 @@
**
** Note that this won't handle all the _allowed_ HTTP formats, just the
** most popular one (the one generated by cgi_rfc822_datestamp(), actually).
*/
time_t cgi_rfc822_parsedate(const char *zDate){
- struct tm t;
- char zIgnore[16];
- char zMonth[16];
-
- memset(&t, 0, sizeof(t));
- if( 7==sscanf(zDate, "%12[A-Za-z,] %d %12[A-Za-z] %d %d:%d:%d", zIgnore,
- &t.tm_mday, zMonth, &t.tm_year, &t.tm_hour, &t.tm_min,
- &t.tm_sec)){
-
- if( t.tm_year > 1900 ) t.tm_year -= 1900;
- for(t.tm_mon=0; azMonths[t.tm_mon]; t.tm_mon++){
- if( !fossil_strnicmp( azMonths[t.tm_mon], zMonth, 3 )){
- return mkgmtime(&t);
- }
- }
- }
-
- return 0;
-}
-
-/*
-** Convert a struct tm* that represents a moment in UTC into the number
-** of seconds in 1970, UTC.
-*/
-time_t mkgmtime(struct tm *p){
- time_t t;
- int nDay;
- int isLeapYr;
- /* Days in each month: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
- static int priorDays[] = { 0, 31, 59, 90,120,151,181,212,243,273,304,334 };
- if( p->tm_mon<0 ){
- int nYear = (11 - p->tm_mon)/12;
- p->tm_year -= nYear;
- p->tm_mon += nYear*12;
- }else if( p->tm_mon>11 ){
- p->tm_year += p->tm_mon/12;
- p->tm_mon %= 12;
- }
- isLeapYr = p->tm_year%4==0 && (p->tm_year%100!=0 || (p->tm_year+300)%400==0);
- p->tm_yday = priorDays[p->tm_mon] + p->tm_mday - 1;
- if( isLeapYr && p->tm_mon>1 ) p->tm_yday++;
- nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 +
- (p->tm_year+300)/400 + p->tm_yday;
- t = ((nDay*24 + p->tm_hour)*60 + p->tm_min)*60 + p->tm_sec;
- return t;
+ int mday, mon, year, yday, hour, min, sec;
+ char zIgnore[4];
+ char zMonth[4];
+ static const char *const azMonths[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};
+ if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore,
+ &mday, zMonth, &year, &hour, &min, &sec)){
+ if( year > 1900 ) year -= 1900;
+ for(mon=0; azMonths[mon]; mon++){
+ if( !strncmp( azMonths[mon], zMonth, 3 )){
+ int nDay;
+ int isLeapYr;
+ static int priorDays[] =
+ { 0, 31, 59, 90,120,151,181,212,243,273,304,334 };
+ if( mon<0 ){
+ int nYear = (11 - mon)/12;
+ year -= nYear;
+ mon += nYear*12;
+ }else if( mon>11 ){
+ year += mon/12;
+ mon %= 12;
+ }
+ isLeapYr = year%4==0 && (year%100!=0 || (year+300)%400==0);
+ yday = priorDays[mon] + mday - 1;
+ if( isLeapYr && mon>1 ) yday++;
+ nDay = (year-70)*365 + (year-69)/4 - year/100 + (year+300)/400 + yday;
+ return ((time_t)(nDay*24 + hour)*60 + min)*60 + sec;
+ }
+ }
+ }
+ return 0;
}
/*
** Check the objectTime against the If-Modified-Since request header. If the
** object time isn't any newer than the header, we immediately send back
Index: src/checkin.c
==================================================================
--- src/checkin.c
+++ src/checkin.c
@@ -472,11 +472,11 @@
const char *zIgnoreFlag = find_option("ignore", 0, 1);
unsigned scanFlags = 0;
unsigned flags = 0;
int vid, i;
- fossil_pledge("stdio rpath wpath cpath id flock tty chown");
+ fossil_pledge("stdio rpath wpath cpath fattr id flock tty chown");
/* Load affirmative flag options. */
for( i=0; i"),
+ g.zLocalRoot);
}
blob_write_to_file(&report, "-");
}else if( verboseFlag ){
fossil_print(" (none)\n");
}
@@ -865,11 +866,11 @@
blob_zero(&report);
status_report(&report, flags);
if( blob_size(&report) ){
if( showHdr ){
- fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
+ fossil_print("Extras for %s at %s:\n", db_get("project-name",""),
g.zLocalRoot);
}
blob_write_to_file(&report, "-");
}
blob_reset(&report);
Index: src/clone.c
==================================================================
--- src/clone.c
+++ src/clone.c
@@ -317,14 +317,16 @@
@ you "Download Zip" privileges.
}
}else{
const char *zDLTag = db_get("download-tag","trunk");
const char *zNm = db_get("short-project-name","download");
- char *zUrl = href("%R/zip/%t.zip?uuid=%t", zNm, zDLTag);
+ char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm);
@
You are not authorized to clone this repository.
if( g.zLogin==0 || g.zLogin[0]==0 ){
@ Maybe you would be able to clone if you
Index: src/cookies.c
==================================================================
--- src/cookies.c
+++ src/cookies.c
@@ -173,11 +173,11 @@
/* Update the user preferences cookie, if necessary, and shut down this
** module
*/
void cookie_render(void){
- if( cookies.bChanged ){
+ if( cookies.bChanged && P("udc")!=0 ){
Blob new;
int i;
blob_init(&new, 0, 0);
for(i=0;i0 ) blob_append(&new, ",", 1);
Index: src/cson_amalgamation.c
==================================================================
--- src/cson_amalgamation.c
+++ src/cson_amalgamation.c
@@ -322,11 +322,11 @@
#endif
#define true 1
#define false 0
-#define __ -1 /* the universal error code */
+#define XX -1 /* the universal error code */
/* values chosen so that the object size is approx equal to one page (4K) */
#ifndef JSON_PARSER_STACK_SIZE
# define JSON_PARSER_STACK_SIZE 128
#endif
@@ -414,14 +414,14 @@
/*
This array maps the 128 ASCII characters into character classes.
The remaining Unicode characters should be mapped to C_ETC.
Non-whitespace control characters are errors.
*/
- __, __, __, __, __, __, __, __,
- __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __,
- __, __, __, __, __, __, __, __,
- __, __, __, __, __, __, __, __,
+ XX, XX, XX, XX, XX, XX, XX, XX,
+ XX, C_WHITE, C_WHITE, XX, XX, C_WHITE, XX, XX,
+ XX, XX, XX, XX, XX, XX, XX, XX,
+ XX, XX, XX, XX, XX, XX, XX, XX,
C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_STAR, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH,
C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
@@ -448,11 +448,11 @@
KE, /* key */
CO, /* colon */
VA, /* value */
AR, /* array */
ST, /* string */
- ES, /* escape */
+ ESC, /* escape */
U1, /* u1 */
U2, /* u2 */
U3, /* u3 */
U4, /* u4 */
MI, /* minus */
@@ -506,46 +506,46 @@
negative number. A JSON text is accepted if at the end of the text the
state is OK and if the mode is MODE_DONE.
white 1-9 ABCDF etc
space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E | * */
-/*start GO*/ {GO,GO,-6,__,-5,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*object OB*/ {OB,OB,__,-9,__,__,__,__,SB,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*key KE*/ {KE,KE,__,__,__,__,__,__,SB,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*value VA*/ {VA,VA,-6,__,-5,__,__,__,SB,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,FA,__,NU,__,__,TR,__,__,__,__,__},
-/*array AR*/ {AR,AR,-6,__,-5,-7,__,__,SB,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,FA,__,NU,__,__,TR,__,__,__,__,__},
-/*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,EX,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
-/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__,__},
-/*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__,__},
-/*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__,__},
-/*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__,__},
-/*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,UC,UC,UC,UC,UC,UC,UC,UC,__,__,__,__,__,__,UC,UC,__,__},
-/*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IT,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,DF,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*int IT*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,DF,IT,IT,__,__,__,__,DE,__,__,__,__,__,__,__,__,DE,__,__},
-/*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__,__},
-/*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__,__},
-/*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__,__},
-/*true T3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__},
-/*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__,__},
-/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__,__},
-/*false F4*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__},
-/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__,__},
-/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__,__},
-/*null N3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__},
-/*/ C1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,C2},
+/*start GO*/ {GO,GO,-6,XX,-5,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*ok OK*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*object OB*/ {OB,OB,XX,-9,XX,XX,XX,XX,SB,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*key KE*/ {KE,KE,XX,XX,XX,XX,XX,XX,SB,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*colon CO*/ {CO,CO,XX,XX,XX,XX,-2,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*value VA*/ {VA,VA,-6,XX,-5,XX,XX,XX,SB,XX,CB,XX,MX,XX,ZX,IX,XX,XX,XX,XX,XX,FA,XX,NU,XX,XX,TR,XX,XX,XX,XX,XX},
+/*array AR*/ {AR,AR,-6,XX,-5,-7,XX,XX,SB,XX,CB,XX,MX,XX,ZX,IX,XX,XX,XX,XX,XX,FA,XX,NU,XX,XX,TR,XX,XX,XX,XX,XX},
+/*string ST*/ {ST,XX,ST,ST,ST,ST,ST,ST,-4,EX,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
+/*escape ES*/ {XX,XX,XX,XX,XX,XX,XX,XX,ST,ST,ST,XX,XX,XX,XX,XX,XX,ST,XX,XX,XX,ST,XX,ST,ST,XX,ST,U1,XX,XX,XX,XX},
+/*u1 U1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U2,U2,U2,U2,U2,U2,U2,U2,XX,XX,XX,XX,XX,XX,U2,U2,XX,XX},
+/*u2 U2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U3,U3,U3,U3,U3,U3,U3,U3,XX,XX,XX,XX,XX,XX,U3,U3,XX,XX},
+/*u3 U3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U4,U4,U4,U4,U4,U4,U4,U4,XX,XX,XX,XX,XX,XX,U4,U4,XX,XX},
+/*u4 U4*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,UC,UC,UC,UC,UC,UC,UC,UC,XX,XX,XX,XX,XX,XX,UC,UC,XX,XX},
+/*minus MI*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,ZE,IT,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*zero ZE*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,DF,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*int IT*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,DF,IT,IT,XX,XX,XX,XX,DE,XX,XX,XX,XX,XX,XX,XX,XX,DE,XX,XX},
+/*frac FR*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,XX,FR,FR,XX,XX,XX,XX,E1,XX,XX,XX,XX,XX,XX,XX,XX,E1,XX,XX},
+/*e E1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,E2,E2,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*ex E2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*exp E3*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,XX,XX,XX,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*tr T1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,T2,XX,XX,XX,XX,XX,XX,XX},
+/*tru T2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,T3,XX,XX,XX,XX},
+/*true T3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*fa F1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F2,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*fal F2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F3,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*fals F3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F4,XX,XX,XX,XX,XX,XX},
+/*false F4*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*nu N1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,N2,XX,XX,XX,XX},
+/*nul N2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,N3,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*null N3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*/ C1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C2},
/*/star C2*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
/** C3*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
-/*_. FX*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__,__},
-/*\ D1*/ {__,__,__,__,__,__,__,__,__,D2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
-/*\ D2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U1,__,__,__,__},
+/*_. FX*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,XX,XX,XX,XX,FR,FR,XX,XX,XX,XX,E1,XX,XX,XX,XX,XX,XX,XX,XX,E1,XX,XX},
+/*\ D1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,D2,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX},
+/*\ D2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U1,XX,XX,XX,XX},
};
/*
These modes can be pushed on the stack.
@@ -1050,11 +1050,11 @@
}
if (next_char >= 128) {
next_class = C_ETC;
} else {
next_class = ascii_class[next_char];
- if (next_class <= __) {
+ if (next_class <= XX) {
set_error(jc);
return false;
}
}
@@ -1090,11 +1090,11 @@
}
break;
/* escaped char */
case EX:
jc->escaped = 1;
- jc->state = ES;
+ jc->state = ESC;
break;
/* integer detected by minus */
case MX:
jc->type = JSON_T_INTEGER;
jc->state = MI;
@@ -1401,10 +1401,14 @@
config->malloc = malloc;
config->free = free;
}
}
+#undef XX
+#undef COUNTOF
+#undef parse_buffer_clear
+#undef parse_buffer_pop_back_char
/* end file parser/JSON_parser.c */
/* begin file ./cson.c */
#include
#include /* malloc()/free() */
#include
Index: src/cson_amalgamation.h
==================================================================
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1287,21 +1287,21 @@
its string representation is "null" (without the quotes).
See cson_value_new_bool() for notes regarding the returned
value's memory.
*/
-cson_value * cson_value_null();
+cson_value * cson_value_null( void );
/**
Equivalent to cson_value_new_bool(1).
*/
-cson_value * cson_value_true();
+cson_value * cson_value_true( void );
/**
Equivalent to cson_value_new_bool(0).
*/
-cson_value * cson_value_false();
+cson_value * cson_value_false( void );
/**
Semantically the same as cson_value_new_bool(), but for integers.
*/
cson_value * cson_value_new_integer( cson_int_t v );
@@ -1346,11 +1346,11 @@
Post-conditions: cson_value_is_object(value) will return true.
@see cson_value_new_array()
@see cson_value_free()
*/
-cson_value * cson_value_new_object();
+cson_value * cson_value_new_object( void );
/**
This works like cson_value_new_object() but returns an Object
handle directly.
@@ -1361,17 +1361,17 @@
by passing the Value handle (NOT the Object handle) to
cson_value_free() or passing ownership to a parent container.
Returns NULL on error (out of memory).
*/
-cson_object * cson_new_object();
+cson_object * cson_new_object( void );
/**
Identical to cson_new_object() except that it creates
an Array.
*/
-cson_array * cson_new_array();
+cson_array * cson_new_array( void );
/**
Identical to cson_new_object() except that it creates
a String.
*/
@@ -1403,11 +1403,11 @@
Post-conditions: cson_value_is_array(value) will return true.
@see cson_value_new_object()
@see cson_value_free()
*/
-cson_value * cson_value_new_array();
+cson_value * cson_value_new_array( void );
/**
Frees any resources owned by v, then frees v. If v is a container
type (object or array) its children are also freed (recursively).
Index: src/db.c
==================================================================
--- src/db.c
+++ src/db.c
@@ -1092,10 +1092,17 @@
LOCAL sqlite3 *db_open(const char *zDbName){
int rc;
sqlite3 *db;
if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
+ if( strcmp(zDbName, g.nameOfExe)==0 ){
+ extern int sqlite3_appendvfs_init(
+ sqlite3 *, char **, const sqlite3_api_routines *
+ );
+ sqlite3_appendvfs_init(0,0,0);
+ g.zVfsName = "apndvfs";
+ }
rc = sqlite3_open_v2(
zDbName, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
@@ -2841,11 +2848,11 @@
#endif
/*
** SETTING: auto-captcha boolean default=on variable=autocaptcha
** If enabled, the /login page provides a button that will automatically
** fill in the captcha password. This makes things easier for human users,
-** at the expense of also making logins easier for malecious robots.
+** at the expense of also making logins easier for malicious robots.
*/
/*
** SETTING: auto-hyperlink boolean default=on
** Use javascript to enable hyperlinks on web pages
** for all users (regardless of the "h" privilege) if the
@@ -2914,11 +2921,11 @@
** line endings. Set to "*" to disable CR+LF checking.
** The crnl-glob setting is a compatibility alias.
*/
/*
** SETTING: crnl-glob width=40 versionable block-text
-** This is an alias for the crlf-glob setting
+** This is an alias for the crlf-glob setting.
*/
/*
** SETTING: default-perms width=16 default=u
** Permissions given automatically to new users. For more
** information on permissions see the Users page in Server
@@ -3003,11 +3010,11 @@
** and "ui" commands.
*/
/*
** SETTING: https-login boolean default=off
** If true, then the Fossil web server will redirect unencrypted
-** login screeen requests to HTTPS.
+** login screen requests to HTTPS.
*/
/*
** SETTING: ignore-glob width=40 versionable block-text
** The value is a comma or newline-separated list of GLOB
** patterns specifying files that the "add", "addremove",
@@ -3016,11 +3023,11 @@
** Example: *.log customCode.c notes.txt
*/
/*
** SETTING: keep-glob width=40 versionable block-text
** The value is a comma or newline-separated list of GLOB
-** patterns specifying files that the "clean" command will keep
+** patterns specifying files that the "clean" command will keep.
*/
/*
** SETTING: localauth boolean default=off
** If enabled, require that HTTP connections from
** 127.0.0.1 be authenticated by password. If
Index: src/diff.c
==================================================================
--- src/diff.c
+++ src/diff.c
@@ -2350,12 +2350,12 @@
** Reverse Annotations: Normally, these web pages look at versions of
** FILENAME moving backwards in time back toward the root check-in. However,
** if the origin= query parameter is used to specify some future check-in
** (example: "origin=trunk") then these pages show changes moving towards
** that alternative origin. Thus using "origin=trunk" on an historical
-** version of the file shows the first time each line in the file was been
-** changed in subsequent check-ins.
+** version of the file shows the first time each line in the file was changed
+** or removed by any subsequent check-in.
**
** Query parameters:
**
** checkin=ID The check-in at which to start the annotation
** filename=FILENAME The filename.
@@ -2368,11 +2368,10 @@
** origin=ID The origin checkin. If unspecified, the root
** check-in over the entire repository is used.
** Specify "origin=trunk" or similar for a reverse
** annotation
** w=BOOLEAN Ignore whitespace
-**
*/
void annotation_page(void){
int i;
const char *zLimit; /* Depth limit */
u64 annFlags = DIFF_STRIP_EOLCR;
@@ -2538,12 +2537,12 @@
** FILENAME moving backwards in time back toward the root check-in, and
** thus the output shows the most recent change to each line. However,
** if the -o|--origin option is used to specify some future check-in
** (example: "-o trunk") then these commands show changes moving towards
** that alternative origin. Thus using "-o trunk" on an historical version
-** of the file shows the first time each line in the file was been changed
-** by subsequent check-ins.
+** of the file shows the first time each line in the file was changed or
+** removed by any subsequent check-in.
**
** Options:
** --filevers Show file version numbers rather than
** check-in versions
** -r|--revision VERSION The specific check-in containing the file
Index: src/doc.c
==================================================================
--- src/doc.c
+++ src/doc.c
@@ -639,15 +639,23 @@
}else{
goto doc_not_found;
}
}
if( isUV ){
- if( db_table_exists("repository","unversioned")
- && unversioned_content(zName, &filebody)==0
- ){
- rid = 1;
- zDfltTitle = zName;
+ if( db_table_exists("repository","unversioned") ){
+ Stmt q;
+ db_prepare(&q, "SELECT hash, mtime FROM unversioned"
+ " WHERE name=%Q", zName);
+ if( db_step(&q)==SQLITE_ROW ){
+ etag_check(ETAG_HASH, db_column_text(&q,0));
+ etag_last_modified(db_column_int64(&q,1));
+ }
+ db_finalize(&q);
+ if( unversioned_content(zName, &filebody)==0 ){
+ rid = 1;
+ zDfltTitle = zName;
+ }
}
}else if( fossil_strcmp(zCheckin,"ckout")==0 ){
/* Read from the local checkout */
char *zFullpath;
db_must_be_within_tree();
@@ -839,19 +847,19 @@
*/
void logo_page(void){
Blob logo;
char *zMime;
+ etag_check(ETAG_CONFIG, 0);
zMime = db_get("logo-mimetype", "image/gif");
blob_zero(&logo);
db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
if( blob_size(&logo)==0 ){
blob_init(&logo, (char*)aLogo, sizeof(aLogo));
}
cgi_set_content_type(zMime);
cgi_set_content(&logo);
- g.isConst = 1;
}
/*
** The default background image: a 16x16 white GIF
*/
@@ -873,19 +881,19 @@
*/
void background_page(void){
Blob bgimg;
char *zMime;
+ etag_check(ETAG_CONFIG, 0);
zMime = db_get("background-mimetype", "image/gif");
blob_zero(&bgimg);
db_blob(&bgimg, "SELECT value FROM config WHERE name='background-image'");
if( blob_size(&bgimg)==0 ){
blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
}
cgi_set_content_type(zMime);
cgi_set_content(&bgimg);
- g.isConst = 1;
}
/*
** WEBPAGE: docsrch
ADDED src/etag.c
Index: src/etag.c
==================================================================
--- /dev/null
+++ src/etag.c
@@ -0,0 +1,210 @@
+/*
+** Copyright (c) 2018 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the Simplified BSD License (also
+** known as the "2-Clause License" or "FreeBSD License".)
+**
+** 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.
+**
+** Author contact information:
+** drh@hwaci.com
+** http://www.hwaci.com/drh/
+**
+*******************************************************************************
+**
+** This file implements ETags: cache control for Fossil
+**
+** An ETag is a hash that encodes attributes which must be the same for
+** the page to continue to be valid. Attributes that might be contained
+** in the ETag include:
+**
+** (1) The mtime on the Fossil executable
+** (2) The last change to the CONFIG table
+** (3) The last change to the EVENT table
+** (4) The value of the display cookie
+** (5) A hash value supplied by the page generator
+**
+** Item (1) is always included in the ETag. The other elements are
+** optional. Because (1) is always included as part of the ETag, all
+** outstanding ETags can be invalidated by touching the fossil executable.
+**
+** A page generator routine invokes etag_check() exactly once, with
+** arguments that indicates which of the above elements to include in the
+** hash. If the request contained an If-None-Match header which matches
+** the generated ETag, then a 304 Not Modified reply is generated and
+** the process exits. In other words, etag_check() never returns. But
+** if there is no If-None_Match header or if the ETag does not match,
+** then etag_check() returns normally. Later, during reply generation,
+** the cgi.c module will invoke etag_tag() to recover the generated tag
+** and include it in the reply header.
+**
+** 2018-02-25:
+**
+** Also support Last-Modified: and If-Modified-Since:. The
+** etag_last_modified(mtime) API records a timestamp for the page in
+** seconds since 1970. This causes a Last-Modified: header to be
+** issued in the reply. Or, if the request contained If-Modified-Since:
+** and the new mtime is not greater than the mtime associated with
+** If-Modified-Since, then a 304 Not Modified reply is generated and
+** the etag_last_modified() API never returns.
+*/
+#include "config.h"
+#include "etag.h"
+
+#if INTERFACE
+/*
+** Things to monitor
+*/
+#define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */
+#define ETAG_DATA 0x02 /* Output depends on the EVENT table */
+#define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */
+#define ETAG_HASH 0x08 /* Output depends on a hash */
+#endif
+
+static char zETag[33]; /* The generated ETag */
+static int iMaxAge = 0; /* The max-age parameter in the reply */
+static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
+
+/*
+** Generate an ETag
+*/
+void etag_check(unsigned eFlags, const char *zHash){
+ sqlite3_int64 mtime;
+ const char *zIfNoneMatch;
+ char zBuf[50];
+ assert( zETag[0]==0 ); /* Only call this routine once! */
+
+ iMaxAge = 86400;
+ md5sum_init();
+
+ /* Always include the mtime of the executable as part of the hash */
+ mtime = file_mtime(g.nameOfExe, ExtFILE);
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"mtime: %lld\n", mtime);
+ md5sum_step_text(zBuf, -1);
+
+ if( (eFlags & ETAG_HASH)!=0 && zHash ){
+ md5sum_step_text("hash: ", -1);
+ md5sum_step_text(zHash, -1);
+ md5sum_step_text("\n", 1);
+ iMaxAge = 0;
+ }else if( eFlags & ETAG_DATA ){
+ int iKey = db_int(0, "SELECT max(rcvid) FROM rcvfrom");
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
+ md5sum_step_text("data: ", -1);
+ md5sum_step_text(zBuf, -1);
+ md5sum_step_text("\n", 1);
+ iMaxAge = 60;
+ }else if( eFlags & ETAG_CONFIG ){
+ int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
+ md5sum_step_text("data: ", -1);
+ md5sum_step_text(zBuf, -1);
+ md5sum_step_text("\n", 1);
+ iMaxAge = 3600;
+ }
+
+ /* Include the display cookie */
+ if( eFlags & ETAG_COOKIE ){
+ md5sum_step_text("display-cookie: ", -1);
+ md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
+ md5sum_step_text("\n", 1);
+ iMaxAge = 0;
+ }
+
+ /* Generate the ETag */
+ memcpy(zETag, md5sum_finish(0), 33);
+
+ /* Check to see if the generated ETag matches If-None-Match and
+ ** generate a 304 reply if it does. */
+ zIfNoneMatch = P("HTTP_IF_NONE_MATCH");
+ if( zIfNoneMatch==0 ) return;
+ if( strcmp(zIfNoneMatch,zETag)!=0 ) return;
+
+ /* If we get this far, it means that the content has
+ ** not changed and we can do a 304 reply */
+ cgi_reset_content();
+ cgi_set_status(304, "Not Modified");
+ cgi_reply();
+ fossil_exit(0);
+}
+
+/*
+** Accept a new Last-Modified time. This routine should be called by
+** page generators that know a valid last-modified time. This routine
+** might generate a 304 Not Modified reply and exit(), never returning.
+** Or, if not, it will cause a Last-Modified: header to be included in the
+** reply.
+*/
+void etag_last_modified(sqlite3_int64 mtime){
+ const char *zIfModifiedSince;
+ sqlite3_int64 x;
+ assert( iEtagMtime==0 ); /* Only call this routine once */
+ assert( mtime>0 ); /* Only call with a valid mtime */
+ iEtagMtime = mtime;
+
+ /* Check to see the If-Modified-Since constraint is satisfied */
+ zIfModifiedSince = P("HTTP_IF_MODIFIED_SINCE");
+ if( zIfModifiedSince==0 ) return;
+ x = cgi_rfc822_parsedate(zIfModifiedSince);
+ if( x<=0 || x>mtime ) return;
+
+#if 0
+ /* If the Fossil executable is more recent than If-Modified-Since,
+ ** go ahead and regenerate the resource. */
+ if( file_mtime(g.nameOfExe, ExtFILE)>x ) return;
+#endif
+
+ /* If we reach this point, it means that the resource has not changed
+ ** and that we should generate a 304 Not Modified reply */
+ cgi_reset_content();
+ cgi_set_status(304, "Not Modified");
+ cgi_reply();
+ fossil_exit(0);
+}
+
+/* Return the ETag, if there is one.
+*/
+const char *etag_tag(void){
+ return zETag;
+}
+
+/* Return the recommended max-age
+*/
+int etag_maxage(void){
+ return iMaxAge;
+}
+
+/* Return the last-modified time in seconds since 1970. Or return 0 if
+** there is no last-modified time.
+*/
+sqlite3_int64 etag_mtime(void){
+ return iEtagMtime;
+}
+
+/*
+** COMMAND: test-etag
+**
+** Usage: fossil test-etag -key KEY-NUMBER -hash HASH
+**
+** Generate an etag given a KEY-NUMBER and/or a HASH.
+**
+** KEY-NUMBER is some combination of:
+**
+** 1 ETAG_CONFIG The config table version number
+** 2 ETAG_DATA The event table version number
+** 4 ETAG_COOKIE The display cookie
+*/
+void test_etag_cmd(void){
+ const char *zHash = 0;
+ const char *zKey;
+ int iKey = 0;
+ db_find_and_open_repository(0, 0);
+ zKey = find_option("key",0,1);
+ zHash = find_option("hash",0,1);
+ if( zKey ) iKey = atoi(zKey);
+ etag_check(iKey, zHash);
+ fossil_print("%s\n", etag_tag());
+}
Index: src/export.c
==================================================================
--- src/export.c
+++ src/export.c
@@ -600,17 +600,20 @@
db_finalize(&q2);
db_finalize(&q3);
/* Output the commit records.
*/
+ topological_sort_checkins(0);
db_prepare(&q,
"SELECT strftime('%%s',mtime), objid, coalesce(ecomment,comment),"
" coalesce(euser,user),"
" (SELECT value FROM tagxref WHERE rid=objid AND tagid=%d)"
- " FROM event"
- " WHERE type='ci' AND NOT EXISTS (SELECT 1 FROM oldcommit WHERE objid=rid)"
- " ORDER BY mtime ASC",
+ " FROM toponode, event"
+ " WHERE toponode.tid=event.objid"
+ " AND event.type='ci'"
+ " AND NOT EXISTS (SELECT 1 FROM oldcommit WHERE toponode.tid=rid)"
+ " ORDER BY toponode.tseq ASC",
TAG_BRANCH
);
db_prepare(&q2, "INSERT INTO oldcommit VALUES (:rid)");
while( db_step(&q)==SQLITE_ROW ){
Stmt q4;
@@ -623,11 +626,13 @@
bag_insert(&vers, ckinId);
db_bind_int(&q2, ":rid", ckinId);
db_step(&q2);
db_reset(&q2);
- if( zBranch==0 || fossil_strcmp(zBranch, "trunk")==0 ) zBranch = gexport.zTrunkName;
+ if( zBranch==0 || fossil_strcmp(zBranch, "trunk")==0 ){
+ zBranch = gexport.zTrunkName;
+ }
zMark = mark_name_from_rid(ckinId, &unused_mark);
printf("commit refs/heads/");
print_ref(zBranch);
printf("\nmark %s\n", zMark);
free(zMark);
@@ -737,5 +742,98 @@
}
}
bag_clear(&blobs);
bag_clear(&vers);
}
+
+/*
+** Construct the temporary table toposort as follows:
+**
+** CREATE TEMP TABLE toponode(
+** tid INTEGER PRIMARY KEY, -- Check-in id
+** tseq INT -- integer total order on check-ins.
+** );
+**
+** This table contains all check-ins of the repository in topological
+** order. "Topological order" means that every parent check-in comes
+** before all of its children. Topological order is *almost* the same
+** thing as "ORDER BY event.mtime". Differences only arrise when there
+** are timewarps. In as much as Git hates timewarps, we have to compute
+** a correct topological order when doing an export.
+**
+** Since mtime is a usually already nearly in topological order, the
+** algorithm is to start with mtime, then make adjustments as necessary
+** for timewarps. This is not a great algorithm for the general case,
+** but it is very fast for the overwhelmingly common case where there
+** are few timewarps.
+*/
+int topological_sort_checkins(int bVerbose){
+ int nChange = 0;
+ Stmt q1;
+ Stmt chng;
+ db_multi_exec(
+ "CREATE TEMP TABLE toponode(\n"
+ " tid INTEGER PRIMARY KEY,\n"
+ " tseq INT\n"
+ ");\n"
+ "INSERT INTO toponode(tid,tseq) "
+ " SELECT objid, CAST(mtime*8640000 AS int) FROM event WHERE type='ci';\n"
+ "CREATE TEMP TABLE topolink(\n"
+ " tparent INT,\n"
+ " tchild INT,\n"
+ " PRIMARY KEY(tparent,tchild)\n"
+ ") WITHOUT ROWID;"
+ "INSERT INTO topolink(tparent,tchild)"
+ " SELECT pid, cid FROM plink;\n"
+ "CREATE INDEX topolink_child ON topolink(tchild);\n"
+ );
+
+ /* Find a timewarp instance */
+ db_prepare(&q1,
+ "SELECT P.tseq, C.tid, C.tseq\n"
+ " FROM toponode P, toponode C, topolink X\n"
+ " WHERE X.tparent=P.tid\n"
+ " AND X.tchild=C.tid\n"
+ " AND P.tseq>=C.tseq;"
+ );
+
+ /* Update the timestamp on :tid to have value :tseq */
+ db_prepare(&chng,
+ "UPDATE toponode SET tseq=:tseq WHERE tid=:tid"
+ );
+
+ while( db_step(&q1)==SQLITE_ROW ){
+ i64 iParentTime = db_column_int64(&q1, 0);
+ int iChild = db_column_int(&q1, 1);
+ i64 iChildTime = db_column_int64(&q1, 2);
+ nChange++;
+ if( nChange>10000 ){
+ fossil_fatal("failed to fix all timewarps after 100000 attempts");
+ }
+ db_reset(&q1);
+ db_bind_int64(&chng, ":tid", iChild);
+ db_bind_int64(&chng, ":tseq", iParentTime+1);
+ db_step(&chng);
+ db_reset(&chng);
+ if( bVerbose ){
+ fossil_print("moving %d from %lld to %lld\n",
+ iChild, iChildTime, iParentTime+1);
+ }
+ }
+
+ db_finalize(&q1);
+ db_finalize(&chng);
+ return nChange;
+}
+
+/*
+** COMMAND: test-topological-sort
+**
+** Invoke the topological_sort_checkins() interface for testing
+** purposes.
+*/
+void test_topological_sort(void){
+ int n;
+ db_find_and_open_repository(0, 0);
+ n = topological_sort_checkins(1);
+ fossil_print("%d reorderings required\n", n);
+}
Index: src/graph.c
==================================================================
--- src/graph.c
+++ src/graph.c
@@ -37,11 +37,11 @@
int rid; /* The rid for the check-in */
i8 nParent; /* Number of parents. -1 for technote lines */
int *aParent; /* Array of parents. 0 element is primary .*/
char *zBranch; /* Branch name */
char *zBgClr; /* Background Color */
- char zUuid[41]; /* Check-in for file ID */
+ char zUuid[HNAME_MAX+1]; /* Check-in for file ID */
GraphRow *pNext; /* Next row down in the list of all rows */
GraphRow *pPrev; /* Previous row */
int idx; /* Row index. First is 1. 0 used for "none" */
Index: src/import.c
==================================================================
--- src/import.c
+++ src/import.c
@@ -517,10 +517,11 @@
}
static struct{
const char *zMasterName; /* Name of master branch */
+ int authorFlag; /* Use author as checkin committer */
} ggit;
/*
** Read the git-fast-import format from pIn and insert the corresponding
** content into the database.
@@ -619,19 +620,23 @@
gg.aData = 0;
gg.nData = 0;
}
}
}else
- if( strncmp(zLine, "author ", 7)==0 ){
+ if( (!ggit.authorFlag && strncmp(zLine, "author ", 7)==0)
+ || (ggit.authorFlag && strncmp(zLine, "committer ",10)==0
+ && gg.zUser!=NULL) ){
/* No-op */
}else
if( strncmp(zLine, "mark ", 5)==0 ){
trim_newline(&zLine[5]);
fossil_free(gg.zMark);
gg.zMark = fossil_strdup(&zLine[5]);
}else
- if( strncmp(zLine, "tagger ", 7)==0 || strncmp(zLine, "committer ",10)==0 ){
+ if( strncmp(zLine, "tagger ", 7)==0
+ || (ggit.authorFlag && strncmp(zLine, "author ", 7)==0)
+ || strncmp(zLine, "committer ",10)==0 ){
sqlite3_int64 secSince1970;
z = strchr(zLine, ' ');
while( fossil_isspace(*z) ) z++;
if( (zTo=strchr(z, '>'))==NULL ) goto malformed_line;
*(++zTo) = '\0';
@@ -1603,10 +1608,11 @@
** --git Import from the git-fast-export file format (default)
** Options:
** --import-marks FILE Restore marks table from FILE
** --export-marks FILE Save marks table to FILE
** --rename-master NAME Renames the master branch to NAME
+** --use-author Uses author as the committer
**
** --svn Import from the svnadmin-dump file format. The default
** behaviour (unless overridden by --flat) is to treat 3
** folders in the SVN root as special, following the
** common layout of SVN repositories. These are (by
@@ -1727,10 +1733,11 @@
markfile_in = find_option("import-marks", 0, 1);
markfile_out = find_option("export-marks", 0, 1);
if( !(ggit.zMasterName = find_option("rename-master", 0, 1)) ){
ggit.zMasterName = "master";
}
+ ggit.authorFlag = find_option("use-author", 0, 0)!=0;
}
verify_all_options();
if( g.argc!=3 && g.argc!=4 ){
usage("--git|--svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?");
Index: src/info.c
==================================================================
--- src/info.c
+++ src/info.c
@@ -714,15 +714,15 @@
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
- zUrl = mprintf("%R/tarball/%t-%S.tar.gz?r=%s", zPJ, zUuid, zUuid);
+ zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid);
@
fossil_free(zUrl);
blob_reset(&projName);
}
@@ -1464,11 +1464,10 @@
" ORDER BY mtime DESC /*sort*/",
rid
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTarget = db_column_text(&q, 0);
- int nTarget = db_column_bytes(&q, 0);
const char *zFilename = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 2);
const char *zUser = db_column_text(&q, 3);
/* const char *zSrc = db_column_text(&q, 4); */
if( cnt>0 ){
@@ -1475,11 +1474,11 @@
@ Also attachment "%h(zFilename)" to
}else{
@ Attachment "%h(zFilename)" to
}
objType |= OBJTYPE_ATTACHMENT;
- if( nTarget==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
+ if( fossil_is_uuid(zTarget) ){
if ( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
zTarget)
){
if( g.perm.Hyperlink && g.anon.RdTkt ){
@ ticket [%z(href("%R/tktview?name=%!S",zTarget))%S(zTarget)]
@@ -2185,11 +2184,11 @@
*/
void tinfo_page(void){
int rid;
char *zDate;
const char *zUuid;
- char zTktName[UUID_SIZE+1];
+ char zTktName[HNAME_MAX+1];
Manifest *pTktChng;
int modPending;
const char *zModAction;
char *zTktTitle;
login_check_credentials();
@@ -2206,11 +2205,11 @@
}
}
pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTktChng==0 ) fossil_redirect_home();
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
- memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
+ sqlite3_snprintf(sizeof(zTktName), zTktName, "%s", pTktChng->zTicketUuid);
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
if( strcmp(zModAction,"delete")==0 ){
moderation_disapprove(rid);
/*
** Next, check if the ticket still exists; if not, we cannot
@@ -2618,11 +2617,11 @@
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
zHideFlag = P("hide") ? " checked" : "";
- if( P("apply") ){
+ if( P("apply") && cgi_csrf_safe(1) ){
Blob ctrl;
char *zNow;
login_verify_csrf_secret();
blob_zero(&ctrl);
Index: src/json_timeline.c
==================================================================
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -318,22 +318,23 @@
cson_value * json_get_changed_files(int rid, int flags){
cson_value * rowsV = NULL;
cson_array * rows = NULL;
Stmt q = empty_Stmt;
db_prepare(&q,
- "SELECT (pid==0) AS isnew,"
- " (fid==0) AS isdel,"
- " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
- " blob.uuid as uuid,"
- " (SELECT uuid FROM blob WHERE rid=pid) as parent,"
- " blob.size as size"
- " FROM mlink, blob"
- " WHERE mid=%d AND pid!=fid"
- " AND blob.rid=fid AND NOT mlink.isaux"
- " ORDER BY name /*sort*/",
- rid
- );
+ "SELECT (pid<=0) AS isnew,"
+ " (fid==0) AS isdel,"
+ " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
+ " (SELECT uuid FROM blob WHERE rid=fid) as uuid,"
+ " (SELECT uuid FROM blob WHERE rid=pid) as parent,"
+ " blob.size as size"
+ " FROM mlink"
+ " LEFT JOIN blob ON blob.rid=fid"
+ " WHERE mid=%d AND pid!=fid"
+ " AND NOT mlink.isaux"
+ " ORDER BY name /*sort*/",
+ rid
+ );
while( (SQLITE_ROW == db_step(&q)) ){
cson_value * rowV = cson_value_new_object();
cson_object * row = cson_value_get_object(rowV);
int const isNew = db_column_int(&q,0);
int const isDel = db_column_int(&q,1);
Index: src/login.c
==================================================================
--- src/login.c
+++ src/login.c
@@ -502,14 +502,28 @@
const char *zReferer;
login_check_credentials();
if( login_wants_https_redirect() ){
const char *zQS = P("QUERY_STRING");
+ if( P("redir")!=0 ){
+ style_header("Insecure Connection");
+ @
Unable To Establish An Encrypted Connection
+ @
This website requires that login credentials be sent over
+ @ an encrypted connection. The current connection is not encrypted
+ @ across the entire route between your browser and the server.
+ @ An attempt was made to redirect to %h(g.zHttpsURL) but
+ @ the connection is still insecure even after the redirect.
+ @
This is probably some kind of configuration problem. Please
+ @ contact your sysadmin.
+ @ Warning: Your password will be sent in the clear over an
+ @ unencrypted connection.
+ if( g.sslNotAvailable ){
+ @ No encrypted connection is available on this server.
+ }else{
+ @ Consider logging in at
+ @ %h(g.zHttpsURL) instead.
+ }
+ @
}
@
@
@
Password:
@
@@ -1337,11 +1364,11 @@
{
const char *zUrl = PD("REQUEST_URI", "index");
const char *zQS = P("QUERY_STRING");
Blob redir;
blob_init(&redir, 0, 0);
- if( login_wants_https_redirect() ){
+ if( login_wants_https_redirect() && !g.sslNotAvailable ){
blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zUrl);
}else{
blob_appendf(&redir, "%R/login?g=%T", zUrl);
}
if( anonOk ) blob_append(&redir, "&anon", 5);
Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -49,20 +49,10 @@
#ifdef FOSSIL_ENABLE_JSON
# include "cson_amalgamation.h" /* JSON API. */
# include "json_detail.h"
#endif
-/*
-** Size of a UUID in characters. A UUID is a randomly generated
-** lower-case hexadecimal number used to identify tickets.
-**
-** In Fossil 1.x, UUID also referred to a SHA1 artifact hash. But that
-** usage is now obsolete. The term UUID should now mean only a very large
-** random number used as a unique identifier for tickets or other objects.
-*/
-#define UUID_SIZE 40
-
/*
** Maximum number of auxiliary parameters on reports
*/
#define MX_AUX 5
@@ -516,10 +506,14 @@
#ifdef __APPLE__
/* Disable the file alias warning on apple products because Time Machine
** creates lots of aliases and the warning alarms people. */
if( iCode==SQLITE_WARNING ) return;
#endif
+#ifndef FOSSIL_DEBUG
+ /* Disable the automatic index warning except in FOSSIL_DEBUG builds. */
+ if( iCode==SQLITE_WARNING_AUTOINDEX ) return;
+#endif
if( iCode==SQLITE_SCHEMA ) return;
if( g.dbIgnoreErrors ) return;
#ifdef SQLITE_READONLY_DIRECTORY
if( iCode==SQLITE_READONLY_DIRECTORY ){
zErrmsg = "database is in a read-only directory";
@@ -540,10 +534,29 @@
g.comFmtFlags = atoi(zValue);
}else{
g.comFmtFlags = COMMENT_PRINT_DEFAULT;
}
}
+
+/*
+** Check to see if the Fossil binary contains an appended repository
+** file using the appendvfs extension. If so, change command-line arguments
+** to cause Fossil to launch with "fossil ui" on that repo.
+*/
+static int fossilExeHasAppendedRepo(void){
+ extern int deduceDatabaseType(const char*,int);
+ if( 2==deduceDatabaseType(g.nameOfExe,0) ){
+ static char *azAltArgv[] = { 0, "ui", 0, 0 };
+ azAltArgv[0] = g.nameOfExe;
+ azAltArgv[2] = g.nameOfExe;
+ g.argv = azAltArgv;
+ g.argc = 3;
+ return 1;
+ }else{
+ return 0;
+ }
+}
/*
** This procedure runs first.
*/
#if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
@@ -604,11 +617,11 @@
}
}
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
- }else if( g.argc<2 ){
+ }else if( g.argc<2 && !fossilExeHasAppendedRepo() ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
" or: %s help COMMAND -- for help with the named command\n",
g.argv[0], g.argv[0], g.argv[0]);
@@ -930,16 +943,20 @@
#if defined(FOSSIL_ENABLE_TCL)
int rc;
const char *zRc;
#endif
Stmt q;
+ size_t pageSize = 0;
blob_zero(pOut);
blob_appendf(pOut, "This is fossil version %s\n", get_version());
if( !bVerbose ) return;
blob_appendf(pOut, "Compiled on %s %s using %s (%d-bit)\n",
__DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
blob_appendf(pOut, "Schema version %s\n", AUX_SCHEMA_MAX);
+ fossil_get_page_size(&pageSize);
+ blob_appendf(pOut, "Detected memory page size is %lu bytes\n",
+ (unsigned long)pageSize);
#if defined(FOSSIL_ENABLE_MINIZ)
blob_appendf(pOut, "miniz %s, loaded %s\n", MZ_VERSION, mz_version());
#else
blob_appendf(pOut, "zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
#endif
@@ -1002,10 +1019,13 @@
blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
#endif
#if defined(HAVE_PLEDGE)
blob_append(pOut, "HAVE_PLEDGE\n", -1);
#endif
+#if defined(USE_MMAN_H)
+ blob_append(pOut, "USE_MMAN_H\n", -1);
+#endif
#if defined(USE_SEE)
blob_append(pOut, "USE_SEE\n", -1);
#endif
#if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES)
blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n");
@@ -1284,46 +1304,92 @@
@
@
n = db_int(0, "SELECT count(*) FROM sfile");
if( n>0 ){
Stmt q;
- @
Available Repositories:
- @
+ sqlite3_int64 iNow, iMTime;
+ @
Fossil Repositories
+ @
+ @
Filename
Last Modified
+ @
db_prepare(&q, "SELECT pathname"
" FROM sfile ORDER BY pathname COLLATE nocase;");
+ iNow = db_int64(0, "SELECT strftime('%%s','now')");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
int nName = (int)strlen(zName);
char *zUrl;
+ char *zAge;
+ char *zFull;
if( nName<7 ) continue;
zUrl = sqlite3_mprintf("%.*s", nName-7, zName);
+ if( zName[0]=='/'
+#ifdef _WIN32
+ || sqlite3_strglob("[a-zA-Z]:/*", zName)==0
+#endif
+ ){
+ zFull = mprintf("%s", zName);
+ }else if ( allRepo ){
+ zFull = mprintf("/%s", zName);
+ }else{
+ zFull = mprintf("%s/%s", g.zRepositoryName, zName);
+ }
+ iMTime = file_mtime(zFull, ExtFILE);
+ fossil_free(zFull);
+ if( iMTime<=0 ){
+ zAge = mprintf("...");
+ }else{
+ zAge = human_readable_age((iNow - iMTime)/86400.0);
+ }
if( sqlite3_strglob("*.fossil", zName)!=0 ){
/* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands
** do not work for repositories whose names do not end in ".fossil".
** So do not hyperlink those cases. */
- @
%h(zName)
+ @
%h(zName)
} else if( sqlite3_strglob("*/.*", zName)==0 ){
/* Do not show hidden repos */
- @