Index: src/browse.c ================================================================== --- src/browse.c +++ src/browse.c @@ -212,21 +212,21 @@ ** Subdirectory names begin with "/". This causes them to sort ** first and it also gives us an easy way to distinguish files ** from directories in the loop that follows. */ db_multi_exec( - "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);" + "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u, l);" ); if( zCI ){ Stmt ins; ManifestFile *pFile; ManifestFile *pPrev = 0; int nPrev = 0; int c; db_prepare(&ins, - "INSERT OR IGNORE INTO localfiles VALUES(pathelement(:x,0), :u)" + "INSERT OR IGNORE INTO localfiles VALUES(pathelement(:x,0), :u, :l)" ); manifest_file_rewind(pM); while( (pFile = manifest_file_next(pM,0))!=0 ){ if( nD>0 && (fossil_strncmp(pFile->zName, zD, nD-1)!=0 @@ -240,10 +240,11 @@ ){ continue; } db_bind_text(&ins, ":x", &pFile->zName[nD]); db_bind_text(&ins, ":u", pFile->zUuid); + db_bind_int(&ins, ":l", pFile->zPerm && strchr(pFile->zPerm, 'l')!=0); db_step(&ins); db_reset(&ins); pPrev = pFile; for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){} if( c=='/' ) nPrev++; @@ -250,18 +251,18 @@ } db_finalize(&ins); }else if( zD ){ db_multi_exec( "INSERT OR IGNORE INTO localfiles" - " SELECT pathelement(name,%d), NULL FROM filename" + " SELECT pathelement(name,%d,0), NULL FROM filename" " WHERE name GLOB '%q/*'", nD, zD ); }else{ db_multi_exec( "INSERT OR IGNORE INTO localfiles" - " SELECT pathelement(name,0), NULL FROM filename" + " SELECT pathelement(name,0,0), NULL FROM filename" ); } /* Generate a multi-column table listing the contents of zD[] ** directory. @@ -304,41 +305,67 @@ /* If the directory contains a readme file, then display its content below ** the list of files */ db_prepare(&q, - "SELECT x, u FROM localfiles" + "SELECT x, u, l FROM localfiles" " WHERE x COLLATE nocase IN" " ('readme','readme.txt','readme.md','readme.wiki','readme.markdown'," " 'readme.html') ORDER BY x LIMIT 1;" ); if( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q,0); const char *zUuid = db_column_text(&q,1); + int isLink = db_column_int(&q,2); if( zUuid ){ rid = fast_uuid_to_rid(zUuid); - }else{ - if( zD ){ - rid = db_int(0, - "SELECT fid FROM filename, mlink, event" - " WHERE name='%q/%q'" - " AND mlink.fnid=filename.fnid" - " AND event.objid=mlink.mid" - " ORDER BY event.mtime DESC LIMIT 1", - zD, zName - ); - }else{ - rid = db_int(0, - "SELECT fid FROM filename, mlink, event" - " WHERE name='%q'" - " AND mlink.fnid=filename.fnid" - " AND event.objid=mlink.mid" - " ORDER BY event.mtime DESC LIMIT 1", - zName - ); - } - } + }else if( zD ){ + rid = db_int(0, + "SELECT fid FROM filename, mlink, event" + " WHERE name='%q/%q'" + " AND mlink.fnid=filename.fnid" + " AND event.objid=mlink.mid" + " ORDER BY event.mtime DESC LIMIT 1", + zD, zName + ); + }else{ + rid = db_int(0, + "SELECT fid FROM filename, mlink, event" + " WHERE name='%q'" + " AND mlink.fnid=filename.fnid" + " AND event.objid=mlink.mid" + " ORDER BY event.mtime DESC LIMIT 1", + zName + ); + } + + /* If the README file is a symlink, dereference it to find the actual + * document. To keep things simple and to avoid infinite loops, do not + * attempt more than one level of dereferencing. */ + if( rid && isLink ){ + char *zDir, *zNewName; + Blob content; + content_get(rid, &content); + zDir = file_dirname(zName); + if( zDir ){ + zNewName = mprintf("%s/%s", zDir, blob_buffer(&content)); + }else{ + zNewName = blob_buffer(&content); + } + file_simplify_name(zNewName, -1, 0); + rid = db_int(0, + "SELECT fid FROM filename, mlink, event" + " WHERE name='%q'" + " AND mlink.fnid=filename.fnid" + " AND event.objid=mlink.mid" + " ORDER BY event.mtime DESC LIMIT 1", + zNewName + ); + zName = zNewName; + zUuid = 0; + } + if( rid ){ @
if( sqlite3_strlike("readme.html", zName, 0)==0 ){ if( zUuid==0 ){ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -30,10 +30,13 @@ [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to honor the versioned manifest setting when outside of an open checkout directory. * The admin-log and access-log settings are now on by default for new repositories. + * Update /dir to support readme and readme.* files being a symlink to the + actual document. Symlinks to symlinks are not supported in this instance. + The document type is determined by the link target name. * Update the built-in SQLite to version 3.20.1.

Changes for Version 2.3 (2017-07-21)