Download raw body.
gotweb sunset
Here is an initial diff to kill poor, poor neglected gotweb. See anything I've missed here? -- Tracey Emery diff /home/tracey/src/got commit - b1b2091b92cf99c8f0fe87488f2757f4d712e094 path + /home/tracey/src/got blob - 819941027860474c6e36a936822d7c2f9c640bbc file + Makefile --- Makefile +++ Makefile @@ -39,12 +39,6 @@ web: tmpl-regress: ${MAKE} -C regress/template -web: - ${MAKE} -C gotweb - -web-install: - ${MAKE} -C gotweb install - webd: tmpl ${MAKE} -C gotwebd blob - 6e6a2e8391b5ff02c1bdb7753f0ec1b51a1ff8a9 file + README --- README +++ README @@ -79,28 +79,24 @@ Game of Trees Web (Gotweb) is a CGI program which disp See regress/gotd/README for information about running the server test suite. -Game of Trees Web (Gotweb) is a CGI program which displays repository data -and is designed to work with httpd(8) and slowcgi(8). It requires the Kristaps -Dzonsons kcgi library, version 0.12.0 or greater. +Game of Trees Daemon (gotwebd) is a FastCGI program which displays repository +data and is designed to work with httpd(8). -To compile gotweb on OpenBSD, run: +To compile gotwebd on OpenBSD, run: - # pkg_add kcgi - $ make web - # make web-install + $ make webd + # make webd-install This will create the following files: - the CGI program /var/www/cgi-bin/gotweb/gotweb - helper programs from the libexec directory in /var/www/cgi-bin/gotweb/libexec - several template files in /var/www/cgi-bin/gw_tmpl/ - html, css, and image files in /var/www/htdocs/gotweb/ - the directory /var/www/got/tmp/ + the daemon program /usr/local/sbin/gotwebd + css and image files in /var/www/htdocs/gotwebd + the gotwebd init script in /etc/rc.d man pages (only installed if building sources from a Got release tarball) Documentation is available in manual pages: - $ man -l gotweb/gotweb.8 - $ man -l gotweb/gotweb.conf.5 + $ man -l gotwebd/gotwebd.8 + $ man -l gotwebd/gotwebd.conf.5 Got can be built with profiling enabled to debug performance issues. @@ -123,26 +119,7 @@ As another example, to compile gotweb with profiling e $ doas pkg_add gprof2dot graphviz $ gprof ~/bin/got-read-pack gmon.out | gprof2dot | dot -T png > profile.png -As another example, to compile gotweb with profiling enabled: - $ cd gotweb - $ make clean - $ make PROFILE=1 gotweb - $ make # compile remaining gotweb binaries as usual - $ doas make install - $ doas chown www /var/www/cgi-bin/gotweb/ - -After loading a gotweb page in the browser, there should now -be a gmon.out file next to the gotweb binary: - -$ ls -l /var/www/cgi-bin/gotweb/ -total 6088 --rw-r--r-- 1 www daemon 427642 Jun 17 22:04 gmon.out --rwxr-xr-x 1 www www 2630488 Jun 17 22:03 gotweb -drwxr-xr-x 2 root daemon 512 Jun 17 22:03 gw_tmpl -drwxr-xr-x 2 root daemon 512 Jun 17 22:03 libexec - - Guidelines for reporting problems: All problem/bug reports should include a reproduction recipe in form of a blob - ae4b3d19d689e504703a7a34bf04a9ba4607fde8 file + got/got.1 --- got/got.1 +++ got/got.1 @@ -3453,7 +3453,7 @@ create a pull request. .Xr git-repository 5 , .Xr got-worktree 5 , .Xr got.conf 5 , -.Xr gotweb 8 +.Xr gotwebd 8 .Sh AUTHORS .An Anthony J. Bentley Aq Mt bentley@openbsd.org .An Christian Weisgerber Aq Mt naddy@openbsd.org @@ -3477,7 +3477,7 @@ and .Nm , .Xr tog 1 , and -.Xr gotweb 8 +.Xr gotwebd 8 were derived from code under copyright by: .Pp .An Caldera International blob - e85f3f4271c437daae68be411b08e6808d317293 file + got-dist.txt --- got-dist.txt +++ got-dist.txt @@ -41,62 +41,6 @@ /gotsh/Makefile /gotsh/gotsh.1 /gotsh/gotsh.c -/gotweb -/gotweb/Makefile -/gotweb/Makefile.inc -/gotweb/files -/gotweb/files/cgi-bin -/gotweb/files/cgi-bin/gw_tmpl -/gotweb/files/cgi-bin/gw_tmpl/blame.tmpl -/gotweb/files/cgi-bin/gw_tmpl/briefs.tmpl -/gotweb/files/cgi-bin/gw_tmpl/commit.tmpl -/gotweb/files/cgi-bin/gw_tmpl/diff.tmpl -/gotweb/files/cgi-bin/gw_tmpl/err.tmpl -/gotweb/files/cgi-bin/gw_tmpl/index.tmpl -/gotweb/files/cgi-bin/gw_tmpl/summry.tmpl -/gotweb/files/cgi-bin/gw_tmpl/tag.tmpl -/gotweb/files/cgi-bin/gw_tmpl/tags.tmpl -/gotweb/files/cgi-bin/gw_tmpl/tree.tmpl -/gotweb/files/htdocs -/gotweb/files/htdocs/gotweb -/gotweb/files/htdocs/gotweb/android-chrome-192x192.png -/gotweb/files/htdocs/gotweb/android-chrome-384x384.png -/gotweb/files/htdocs/gotweb/apple-touch-icon.png -/gotweb/files/htdocs/gotweb/browserconfig.xml -/gotweb/files/htdocs/gotweb/favicon-16x16.png -/gotweb/files/htdocs/gotweb/favicon-32x32.png -/gotweb/files/htdocs/gotweb/favicon.ico -/gotweb/files/htdocs/gotweb/got.png -/gotweb/files/htdocs/gotweb/got_large.png -/gotweb/files/htdocs/gotweb/gotweb.css -/gotweb/files/htdocs/gotweb/index.html -/gotweb/files/htdocs/gotweb/mstile-150x150.png -/gotweb/files/htdocs/gotweb/safari-pinned-tab.svg -/gotweb/files/htdocs/gotweb/site.webmanifest -/gotweb/gotweb.8 -/gotweb/gotweb.c -/gotweb/gotweb.conf.5 -/gotweb/gotweb.h -/gotweb/libexec -/gotweb/libexec/Makefile -/gotweb/libexec/Makefile.inc -/gotweb/libexec/got-read-blob -/gotweb/libexec/got-read-blob/Makefile -/gotweb/libexec/got-read-commit -/gotweb/libexec/got-read-commit/Makefile -/gotweb/libexec/got-read-gitconfig -/gotweb/libexec/got-read-gitconfig/Makefile -/gotweb/libexec/got-read-gotconfig -/gotweb/libexec/got-read-gotconfig/Makefile -/gotweb/libexec/got-read-object -/gotweb/libexec/got-read-object/Makefile -/gotweb/libexec/got-read-pack -/gotweb/libexec/got-read-pack/Makefile -/gotweb/libexec/got-read-tag -/gotweb/libexec/got-read-tag/Makefile -/gotweb/libexec/got-read-tree -/gotweb/libexec/got-read-tree/Makefile -/gotweb/parse.y /gotwebd /gotwebd/Makefile /gotwebd/Makefile.inc blob - 3f9b3180520b398deed0f58abea911812958de70 file + /dev/null --- gotweb/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -.PATH:${.CURDIR}/../lib - -SUBDIR = libexec - -.include "../got-version.mk" -.include "Makefile.inc" - -PROG = gotweb -SRCS = gotweb.c parse.y blame.c commit_graph.c delta.c diff.c \ - diffreg.c error.c object.c object_cache.c \ - object_idset.c object_parse.c opentemp.c path.c pack.c \ - privsep.c reference.c repository.c sha1.c \ - inflate.c buf.c rcsutil.c diff3.c lockfile.c \ - deflate.c object_create.c delta_cache.c gotconfig.c \ - diff_main.c diff_atomize_text.c diff_myers.c diff_output.c \ - diff_output_plain.c diff_output_unidiff.c \ - diff_output_edscript.c diff_patience.c \ - bloom.c murmurhash2.c sigs.c date.c object_open_privsep.c \ - read_gitconfig_privsep.c read_gotconfig_privsep.c \ - pollfd.c reference_parse.c -MAN = ${PROG}.conf.5 ${PROG}.8 - -CPPFLAGS += -I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} \ - -I${KCGIBASE}/include -LDADD += -L${KCGIBASE}/lib -lkcgihtml -lkcgi -lz -lm -LDSTATIC = ${STATIC} - -.if ${GOT_RELEASE} != "Yes" -NOMAN = Yes -.endif - -realinstall: - if [ ! -d ${DESTDIR}${CGI_DIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${CGI_DIR}; \ - fi - if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \ - fi - ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 ${PROG} \ - ${DESTDIR}${CGI_DIR}/${PROG} - if [ ! -d ${DESTDIR}${TMPL_DIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${TMPL_DIR}; \ - fi - ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ - ${.CURDIR}/files/cgi-bin/gw_tmpl/* ${DESTDIR}${TMPL_DIR} - if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \ - fi - if [ ! -d ${DESTDIR}${TMP_DIR}/. ]; then \ - ${INSTALL} -d -o ${WWWUSR} -g ${WWWGRP} -m 755 ${DESTDIR}${TMP_DIR}; \ - fi - if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \ - fi - ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ - ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR} - -.include <bsd.prog.mk> blob - f6a499dbd885b285605963a25b23076855a8786f file + /dev/null --- gotweb/Makefile.inc +++ /dev/null @@ -1,26 +0,0 @@ -KCGIBASE ?= /usr/local -LDADD += -lz -lutil -LDSTATIC = ${STATIC} -CHROOT_DIR ?= /var/www -GOTWEB_DIR = /cgi-bin/gotweb -LIBEXECDIR = ${GOTWEB_DIR}/libexec -LIBEXEC_DIR = ${CHROOT_DIR}${LIBEXECDIR} -ETC_DIR = ${CHROOT_DIR}/etc -HTTPD_DIR = ${CHROOT_DIR}/htdocs -GOTWEB_TMP_DIR ?= /got/tmp -TMP_DIR = ${CHROOT_DIR}${GOTWEB_TMP_DIR} -PROG_DIR = ${HTTPD_DIR}/${PROG} -CGI_DIR = ${CHROOT_DIR}${GOTWEB_DIR} -TMPL_DIR = ${CGI_DIR}/gw_tmpl -PUB_REPOS_DIR = ${CHROOT_DIR}/got/public -WWWUSR ?= www -WWWGRP ?= www - -CPPFLAGS += -DGOT_TMPDIR=${GOTWEB_TMP_DIR} - -.if defined(PROFILE) -CPPFLAGS += -DPROFILE -DEBUG = -O0 -pg -g -static -.else -DEBUG = -O0 -g -.endif blob - 64237d2f0dec8688ccd27965e4b944d1a3ca6d8e file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/blame.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='blame_title_wrapper'> - <div id='blame_title'>Blame</div> - </div> - <div id='blame_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 53d8e825b7ea9995ba68ecbc6a02e8a75f0ced59 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/briefs.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='briefs_title_wrapper'> - <div id='briefs_title'>Commit Briefs</div> - </div> - <div id='briefs_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - ef504f03cfeb9e20af5a92e2c4d3801ee5cb9650 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/commit.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='commits_title_wrapper'> - <div id='commits_title'>Commits</div> - </div> - <div id='commits_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 6a466f25e20dd30349a4913eab6019f62fbfe04a file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/diff.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='diff_title_wrapper'> - <div id='diff_title'>Commit Diff</div> - </div> - <div id='diff_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 52b2cb624d22803080950f1af69d72ea818f9fd8 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/err.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='err_title_wrapper'> - <div id='err_title'>Error</div> - </div> - <div id='err_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/index.tmpl +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - @@content@@ - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/summry.tmpl +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - @@content@@ - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 1867b81cba52c7f0a18b2b931b0d91b92ad52a85 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/tag.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='tag_title_wrapper'> - <div id='tag_title'>Tag</div> - </div> - <div id='tag_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/tags.tmpl +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - @@content@@ - </div> - @@siteowner@@ - </div> - </body> -</html> blob - f7c5a935c98101e547c6c513143bf0096ae1c610 file + /dev/null --- gotweb/files/cgi-bin/gw_tmpl/tree.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>@@title@@</title> - @@head@@ - </head> - <body> - <div id="gw_body"> - <div id="header"> - @@header@@ - </div> - <div id="site_path"> - @@sitepath@@ - @@search@@ - </div> - <div id="content"> - <div id='tree_title_wrapper'> - <div id='tree_title'>Tree</div> - </div> - <div id='tree_content'> - @@content@@ - </div> - </div> - @@siteowner@@ - </div> - </body> -</html> blob - f841f054bc2941b0cdca7e496ea69621671d6766 file + /dev/null Binary files gotweb/files/htdocs/gotweb/android-chrome-192x192.png and /dev/null differ blob - 653a1510ce933f7fe9fbab2fcd171f04fa0b24cc file + /dev/null Binary files gotweb/files/htdocs/gotweb/android-chrome-384x384.png and /dev/null differ blob - 460aa1299f8e9f37773618bcab2619794416fb49 file + /dev/null Binary files gotweb/files/htdocs/gotweb/apple-touch-icon.png and /dev/null differ blob - b3930d0f047184047cb81d620436d91653438b8b file + /dev/null --- gotweb/files/htdocs/gotweb/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<browserconfig> - <msapplication> - <tile> - <square150x150logo src="/mstile-150x150.png"/> - <TileColor>#da532c</TileColor> - </tile> - </msapplication> -</browserconfig> blob - f6c1a7c289faa4a48e03c97e68b1ba7a11dfddd1 file + /dev/null Binary files gotweb/files/htdocs/gotweb/favicon-16x16.png and /dev/null differ blob - 0ceea8c0eabe73e8d12cf106d73c34abb1999cb2 file + /dev/null Binary files gotweb/files/htdocs/gotweb/favicon-32x32.png and /dev/null differ blob - ee414573031ea5b310539196d2530a1e52d49b64 file + /dev/null Binary files gotweb/files/htdocs/gotweb/favicon.ico and /dev/null differ blob - 33933f80ee46217039804bc96672ede12b352b93 file + /dev/null Binary files gotweb/files/htdocs/gotweb/got.png and /dev/null differ blob - 97ace786464b193baf1cd51e54016aea3016e62f file + /dev/null Binary files gotweb/files/htdocs/gotweb/got_large.png and /dev/null differ blob - eb7e67f6b7ca0ddd442d0f8f38810ba7846efae1 file + /dev/null --- gotweb/files/htdocs/gotweb/gotweb.css +++ /dev/null @@ -1,878 +0,0 @@ -/* - * Copyright (c) 2019 Jerome Kasper <neon.king.fr@gmail.com> - * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* general sections */ - -a { - color: #444444; - text-decoration: none; -} -a:hover { - color: Gold; - text-decoration: none; -} -body { - background-color: #ffffff; - color: #000000; - margin: 0; - padding: 0; - font-family: Arial, sans-serif; -} - -.diff_minus, .diff_submodule { - color: magenta; -} -.diff_plus, .diff_symlink, .diff_author { - color: darkcyan; -} -.diff_chunk_header, .diff_date { - background-color: LightSlateGray; - color: yellow; -} -.diff_meta, .diff_executable, .diff_commit { - color: green; -} -.diff_directory { - color: blue; -} - -.back_white { - background-color: #ffffff; -} -.back_lightgray { - background-color: #d8f3ef; -} - -#refs_str { - background-color: #243647; - color: #ffffff; - font-style: italic; -} -#dotted_line { - clear: left; - float: left; - width: 100%; - border-top: 1px dotted #444444; -} -#solid_line { - clear: left; - float: left; - width: 100%; - border-top: 1px solid #444444; -} -#header { - overflow: auto; - width: 100%; - background-image: linear-gradient(to right, White, LightSlateGray); -} -#header a { - color: #ffffff; - font-size: 1.2em; - text-decoration: none; -} -#header a:hover { - color: Gold; - font-size: 1.2em; - text-decoration: none; -} -#site_path { - clear: left; - float: left; - overflow: auto; - width: 100%; - background-color: #243647; -} -#site_link { - float: left; - width: 40%; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - color: #ffffff; - overflow: hidden; -} -#site_link a { - color: #ffffff; - text-decoration: none; -} -#search { - float: right; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#got_link { - float: left; - padding-bottom: 10px; - padding-top: 10px; -} -#content { - width: 100%; -} -#np_wrapper { - clear: left; - float: left; - width: 100%; - border-bottom: 1px dotted #444444; - background-color: #f5fcfb; - overflow: hidden; -} -#nav_prev { - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - overflow: visible; -} -#nav_next { - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; - text-align: right; - overflow: hidden; -} -#navs_wrapper { - clear: left; - float: left; - width: 100%; - background-color: #ced7e0; -} -#navs { - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; - font-size: .8em; -} -#site_owner_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#site_owner { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#description_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#description { - float: left; - width: 72%; - padding-top: 5px; - padding-bottom: 5px; -} -#repo_owner_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#repo_owner { - float: left; - width: 72%; - padding-top: 5px; - padding-bottom: 5px; -} -#last_change_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#last_change { - float: left; - width: 72%; - padding-top: 5px; - padding-bottom: 5px; -} -#cloneurl_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#cloneurl { - float: left; - width: 72%; - padding-top: 5px; - padding-bottom: 5px; - overflow: auto; - white-space: pre-wrap; -} -#tmpl_err { - clear: left; - float: left; - padding-left: 20px; - padding-top: 20px; - padding-bottom: 20px; - white-space: pre-wrap; -} - -/* headers */ - -#header_commit_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_commit { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} -#header_diff_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_diff { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} -#header_author_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_author { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} -#header_committer_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_committer { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} -#header_age_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_age { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} -#header_commit_msg_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_commit_msg { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; - white-space: pre-wrap; -} -#header_tree_title { - clear: left; - float: left; - width: 6.5em; - padding-left: 10px; - padding-top: 2px; - padding-bottom: 2px; -} -#header_tree { - float: left; - width: 72%; - padding-top: 2px; - padding-bottom: 2px; -} - -/* heads.tmpl */ - -#heads_wrapper { - clear: left; - float: left; - width: 100%; -} -#heads_age { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - float: left; - width: 7.5em; - overflow: auto; -} -#heads_space { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - float: left; - width: 8.5em; - overflow: auto; -} -#head { - float: left; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; -} - -/* err.tmpl */ - -#err_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#err_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#err_content { - clear: left; - float: left; - width: 100%; - padding-left: 20px; - padding-top: 20px; - padding-bottom: 20px; -} - -/* briefs.tmpl */ - -#briefs_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#briefs_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#briefs_content { - clear: left; - float: left; - width: 100%; -} -#briefs_wrapper { - clear: left; - float: left; - width: 100%; -} -#briefs_age { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - float: left; - width: 7.5em; - overflow: auto; -} -#briefs_author { - float: left; - padding-top: 5px; - padding-bottom: 5px; - width: 8.5em; - font-style: italic; - overflow: auto; -} -#briefs_log { - float: left; - padding-left: 10px; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; - width: 65%; -} -/* index.tmpl */ - -#index_header { - clear: left; - float: left; - overflow: auto; - width: 100%; - background-color: Khaki; -} -#index_header_project { - clear: left; - float: left; - width: 20%; - padding: 10px; -} -#index_header_description { - float: left; - width: 30%; - padding: 10px; -} -#index_header_owner { - float: left; - width: 12%; - padding: 10px; -} -#index_header_age { - padding: 10px; - overflow: hidden; -} -#index_wrapper { - clear: left; - float: left; - width: 100%; -} -#index_project { - float: left; - width: 20%; - padding: 10px; - overflow: hidden; -} -#index_project_description { - float: left; - width: 30%; - padding: 10px; - overflow: auto; -} -#index_project_owner { - float: left; - width: 12%; - padding: 10px; - overflow: hidden; -} -#index_project_age { - float: left; - width: 14%; - padding: 10px; - overflow: visible; -} -#index_project a { - color: #444444; - text-decoration: none; -} -#index_project a:hover { - color: SteelBlue; - text-decoration: none; -} -#index_project_navs a { - color: #444444; - text-decoration: none; -} -#index_project_navs a:hover { - color: SteelBlue; - text-decoration: none; -} -#index_next a { - color: #444444; - text-decoration: none; -} -#index_next a:hover { - color: SteelBlue; - text-decoration: none; -} -#index_prev a { - color: #444444; - text-decoration: none; -} -#index_prev a:hover { - color: SteelBlue; - text-decoration: none; -} - -/* commit.tmpl */ - -#commits_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#commits_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#commits_content { - clear: left; - float: left; - width: 100%; -} -#commits_line_wrapper { - clear: left; - float: left; - background-color: #f5fcfb; - padding-top: 3px; - padding-bottom: 3px; - width: 100%; -} -#commit { - clear: left; - float: left; - padding-left: 20px; - padding-top: 20px; - padding-bottom: 20px; - white-space: pre-wrap; -} - -/* blame.tmpl */ - -#blame_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#blame_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#blame_content { - clear: left; - float: left; - width: 100%; -} -#blame_header_wrapper { - float: left; - background-color: #f5fcfb; - width: 100%; -} -#blame_header { - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 2px; - width: 80%; -} -#blame { - clear: left; - float: left; - margin-left: 20px; - margin-top: 20px; - margin-bottom: 20px; - font-family: monospace; - white-space: pre; - overflow: auto; -} -#blame_wrapper { - clear: left; - float: left; - width: 100%; -} -#blame_number { - float: left; - width: 3em; - overflow: hidden; -} -#blame_hash { - float: left; - width: 6em; - overflow: auto; -} -#blame_date { - float: left; - width: 7em; - overflow: auto; -} -#blame_author { - float: left; - width: 6em; - overflow: hidden; -} -#blame_code { - float:left; - width: 50%; - overflow: visible; -} - -/* tree.tmpl */ - -#tree_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#tree_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#tree_content { - clear: left; - float: left; - width: 100%; -} -#tree_header_wrapper { - clear: left; - float: left; - background-color: #f5fcfb; - width: 100%; -} -#tree_header { - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 2px; - width: 80%; -} -#tree { - clear: left; - float: left; - margin-left: 20px; - margin-top: 20px; - margin-bottom: 20px; - font-family: monospace; -} -#tree_wrapper { - clear: left; - float: left; - width: 100%; -} -#tree_line { - clear: left; - float: left; - width: 20em; - padding: 1px; -} -#tree_line_blank { - float: left; - padding: 1px; - width: 8em; -} -#tree_line_navs { - float: left; - text-align: right; - padding: 1px; - width: 8em; -} - -/* tag.tmpl */ - -#tag_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#tag_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#tag_content { - clear: left; - float: left; - width: 100%; -} -#tag_header_wrapper { - clear: left; - float: left; - background-color: #f5fcfb; - width: 100%; -} -#tag_header { - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 2px; - width: 80%; -} -#tag_wrapper { - clear: left; - float: left; - width: 100%; -} -#tag_age { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - float: left; - width: 7.5em; - overflow: auto; -} -#tag { - float: left; - width: 8.5em; - font-style: italic; - padding-top: 5px; - padding-bottom: 5px; -} -#tag_name { - float: left; - padding-left: 10px; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#tag_info_date_title { - clear: left; - float: left; - width: 7.5em; -} -#tag_info_date { - float: left; -} -#tag_info_tagger_title { - clear: left; - float: left; - width: 7.5em; -} -#tag_info_tagger { - float: left; -} -#tag_info { - clear: left; - float: left; - margin-top: 25px; - white-space: pre-wrap; -} - -/* tags.tmpl */ -#tags_info { - clear: left; - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} - - -/* diff.tmpl */ - -#diff_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#diff_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#diff_content { - clear: left; - float: left; - width: 100%; -} -#diff_header_wrapper { - float: left; - background-color: #f5fcfb; - width: 100%; -} -#diff_header { - float: left; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 2px; - width: 80%; -} -#diff { - clear: left; - float: left; - margin-left: 20px; - margin-top: 20px; - margin-bottom: 20px; - font-family: monospace; - white-space: pre; -} - -/* summary.tmpl */ - -#summary_wrapper { - clear: left; - float: left; - width: 100%; - background-color: Khaki; -} -#summary_tags_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#summary_tags_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#summary_tags_content { - clear: left; - float: left; - width: 100%; -} -#summary_heads_title_wrapper { - clear: left; - float: left; - width: 100%; - background-color: LightSlateGray; - color: #ffffff; -} -#summary_heads_title { - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} -#summary_heads_content { - clear: left; - float: left; - width: 100%; -} blob - 791e49544c8c5f82a710137fee5a2a4becaad616 file + /dev/null --- gotweb/files/htdocs/gotweb/index.html +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta http-equiv="Refresh" content="0; url=/cgi-bin/gotweb/gotweb" /> - </head> - <body> - <p><a href="/cgi-bin/gotweb/gotweb">gotweb</a></p> - </body> -</html> \ No newline at end of file blob - 0c47027971e9e0a5060e23fe73e7cb0399eacea8 file + /dev/null Binary files gotweb/files/htdocs/gotweb/mstile-150x150.png and /dev/null differ blob - 96e67c7c4b7cb9b1b395281fae8d7cffa834a991 file + /dev/null --- gotweb/files/htdocs/gotweb/safari-pinned-tab.svg +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" - "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> -<svg version="1.0" xmlns="http://www.w3.org/2000/svg" - width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000" - preserveAspectRatio="xMidYMid meet"> -<metadata> -Created by potrace 1.11, written by Peter Selinger 2001-2013 -</metadata> -<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)" -fill="#000000" stroke="none"> -<path d="M0 1995 l0 -1215 2000 0 2000 0 0 1215 0 1215 -2000 0 -2000 0 0 --1215z"/> -</g> -</svg> blob - a1553eb86b573da072c732c9aabac5a80968461f file + /dev/null --- gotweb/files/htdocs/gotweb/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-384x384.png", - "sizes": "384x384", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} blob - df516d6285a1ca6f473e533e05556b5395d506fe file + /dev/null --- gotweb/gotweb.8 +++ /dev/null @@ -1,155 +0,0 @@ -.\" -.\" Copyright (c) 2020 Stefan Sperling -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate$ -.Dt GOTWEB 8 -.Os -.Sh NAME -.Nm gotweb -.Nd Game of Trees Git repository server for web browsers -.Sh SYNOPSIS -.Nm -.Sh DESCRIPTION -.Nm -provides a web interface allowing Git repository contents to be viewed -with a web browser. -.Pp -.Nm -is a CGI program based on -.Xr got 1 -and -.Xr kcgi 3 -which is intended to run in a -.Xr chroot 2 -environment in -.Pa /var/www . -The program has been designed to work out of the box with -the -.Xr httpd 8 -web server in conjunction with -.Xr slowcgi 8 . -.Pp -Enabling -.Nm -requires the following steps: -.Bl -enum -.It -The -.Xr httpd.conf 5 -configuration file must be adjusted to run -.Nm -as a CGI program with -.Xr slowcgi 8 . -The -.Sx EXAMPLES -section below contains an appropriate configuration file sample. -.It -httpd(8) and slowcgi(8) must be enabled and started: -.Bd -literal -offset indent - # rcctl enable httpd slowcgi - # rcctl start httpd slowcgi -.Ed -.It -Optionally, the run-time behaviour of -.Nm -can be configured via the -.Xr gotweb.conf 5 -configuration file. -.It -Git repositories must be created at a suitable location inside the -web server's -.Xr chroot 2 -environment. -These repositories should -.Em not -be writable by the user ID of the -.Xr httpd 8 -server. -The default location for repositories published by -.Nm -is -.Pa /var/www/got/public . -.It -Git repositories served by -.Nm -should be kept up-to-date with a mechanism such as -.Cm got fetch , -.Xr git-fetch 1 , -or -.Xr rsync 1 , -scheduled by -.Xr cron 8 . -.El -.Sh FILES -.Bl -tag -width /var/www/got/public/ -compact -.It Pa /var/www/got/public/ -Default location for Git repositories served by -.Nm . -This location can be adjusted in the -.Xr gotweb.conf 5 -configuration file. -.It Pa /var/www/cgi-bin/gotweb/gotweb -The -.Nm -CGI program, statically linked for use in a -.Xr chroot 2 -environment. -.It Pa /var/www/cgi-bin/gotweb/gw_tmpl/ -Directory for template files used by -.Nm . -.It Pa /var/www/cgi-bin/gotweb/libexec/ -Directory containing statically linked -.Xr got 1 -helper programs which are run by -.Nm -to read Git repositories. -.It Pa /var/www/htdocs/gotweb/ -Directory containing HTML, CSS, and image files used by -.Nm . -.It Pa /var/www/got/tmp/ -Directory for temporary files created by -.Nm . -.El -.Sh EXAMPLES -Example configuration for httpd.conf: -.Bd -literal -offset indent - - types { include "/usr/share/misc/mime.types" } - server "gotweb.example.com" { - listen on * port 80 - root "/htdocs/gotweb" - location "/cgi-bin/*" { - root "/" - fastcgi - } - location "/*" { - directory index "index.html" - } - } -.Ed -.Sh SEE ALSO -.Xr got 1 , -.Xr kcgi 3 , -.Xr git-repository 5 , -.Xr gotweb.conf 5 , -.Xr httpd 8 , -.Xr slowcgi 8 -.Sh AUTHORS -.An Christian Weisgerber Aq Mt naddy@openbsd.org -.An Jerome Kasper Aq Mt neon.king.fr@gmail.com -.An Josh Rickmar Aq Mt jrick@zettaport.com -.An Omar Polo Aq Mt op@openbsd.org -.An Stefan Sperling Aq Mt stsp@openbsd.org -.An Tracey Emery Aq Mt tracey@traceyemery.net blob - 0580992091e15b774b51ac00db28f4d691a4b1a0 file + /dev/null --- gotweb/gotweb.c +++ /dev/null @@ -1,4989 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net> - * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <ctype.h> -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <regex.h> -#include <sha1.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <got_error.h> -#include <got_object.h> -#include <got_reference.h> -#include <got_repository.h> -#include <got_path.h> -#include <got_cancel.h> -#include <got_worktree.h> -#include <got_diff.h> -#include <got_commit_graph.h> -#include <got_blame.h> -#include <got_privsep.h> -#include <got_opentemp.h> - -#include <kcgi.h> -#include <kcgihtml.h> - -#include "gotweb.h" - -#ifndef nitems -#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) -#endif - -struct gw_trans { - TAILQ_HEAD(headers, gw_header) gw_headers; - TAILQ_HEAD(dirs, gw_dir) gw_dirs; - struct got_repository *repo; - struct gw_dir *gw_dir; - struct gotweb_config *gw_conf; - struct ktemplate *gw_tmpl; - struct khtmlreq *gw_html_req; - struct kreq *gw_req; - const struct got_error *error; - const char *repo_name; - char *repo_path; - char *commit_id; - char *next_id; - char *prev_id; - const char *repo_file; - char *repo_folder; - const char *headref; - unsigned int action; - unsigned int page; - unsigned int repos_total; - enum kmime mime; - int *pack_fds; -}; - -struct gw_header { - TAILQ_ENTRY(gw_header) entry; - struct got_reflist_head refs; - char *path; - - char *refs_str; - char *commit_id; /* id_str1 */ - char *parent_id; /* id_str2 */ - char *tree_id; - char *author; - char *committer; - char *commit_msg; - time_t committer_time; -}; - -struct gw_dir { - TAILQ_ENTRY(gw_dir) entry; - char *name; - char *owner; - char *description; - char *url; - char *age; - char *path; -}; - -enum gw_key { - KEY_ACTION, - KEY_COMMIT_ID, - KEY_FILE, - KEY_FOLDER, - KEY_HEADREF, - KEY_PAGE, - KEY_PATH, - KEY_PREV_ID, - KEY__ZMAX -}; - -enum gw_tmpl { - TEMPL_CONTENT, - TEMPL_HEAD, - TEMPL_HEADER, - TEMPL_SEARCH, - TEMPL_SITEPATH, - TEMPL_SITEOWNER, - TEMPL_TITLE, - TEMPL__MAX -}; - -enum gw_ref_tm { - TM_DIFF, - TM_LONG, -}; - -enum gw_tags_type { - TAGBRIEF, - TAGFULL, -}; - -static const char *const gw_templs[TEMPL__MAX] = { - "content", - "head", - "header", - "search", - "sitepath", - "siteowner", - "title", -}; - -static const struct kvalid gw_keys[KEY__ZMAX] = { - { kvalid_stringne, "action" }, - { kvalid_stringne, "commit" }, - { kvalid_stringne, "file" }, - { kvalid_stringne, "folder" }, - { kvalid_stringne, "headref" }, - { kvalid_int, "page" }, - { kvalid_stringne, "path" }, - { kvalid_stringne, "prev" }, -}; - -static struct gw_header *gw_init_header(void); - -static void gw_free_header(struct gw_header *); - -static int gw_template(size_t, void *); - -static const struct got_error *gw_error(struct gw_trans *); -static const struct got_error *gw_init_gw_dir(struct gw_dir **, const char *); -static const struct got_error *gw_get_repo_description(char **, - struct gw_trans *, char *); -static const struct got_error *gw_get_repo_owner(char **, struct gw_trans *, - char *); -static const struct got_error *gw_get_time_str(char **, time_t, int); -static const struct got_error *gw_get_repo_age(char **, struct gw_trans *, - char *, const char *, int); -static const struct got_error *gw_output_file_blame(struct gw_trans *, - struct gw_header *); -static const struct got_error *gw_output_blob_buf(struct gw_trans *, - struct gw_header *); -static const struct got_error *gw_output_repo_tree(struct gw_trans *, - struct gw_header *); -static const struct got_error *gw_output_diff(struct gw_trans *, - struct gw_header *); -static const struct got_error *gw_output_repo_tags(struct gw_trans *, - struct gw_header *, int, int); -static const struct got_error *gw_output_repo_heads(struct gw_trans *); -static const struct got_error *gw_output_site_link(struct gw_trans *); -static const struct got_error *gw_get_clone_url(char **, struct gw_trans *, - char *); -static const struct got_error *gw_colordiff_line(struct gw_trans *, char *); - -static const struct got_error *gw_gen_commit_header(struct gw_trans *, char *, - char*); -static const struct got_error *gw_gen_diff_header(struct gw_trans *, char *, - char*); -static const struct got_error *gw_gen_author_header(struct gw_trans *, - const char *); -static const struct got_error *gw_gen_age_header(struct gw_trans *, - const char *); -static const struct got_error *gw_gen_committer_header(struct gw_trans *, - const char *); -static const struct got_error *gw_gen_commit_msg_header(struct gw_trans*, - char *); -static const struct got_error *gw_gen_tree_header(struct gw_trans *, char *); -static const struct got_error *gw_display_open(struct gw_trans *, enum khttp, - enum kmime); -static const struct got_error *gw_display_index(struct gw_trans *); -static const struct got_error *gw_get_header(struct gw_trans *, - struct gw_header *, int); -static const struct got_error *gw_get_commits(struct gw_trans *, - struct gw_header *, int, - struct got_object_id *); -static const struct got_error *gw_get_commit(struct gw_trans *, - struct gw_header *, - struct got_commit_object *, - struct got_object_id *); -static const struct got_error *gw_apply_unveil(const char *); -static const struct got_error *gw_blame_cb(void *, int, int, - struct got_commit_object *, - struct got_object_id *); -static const struct got_error *gw_load_got_paths(struct gw_trans *); -static const struct got_error *gw_load_got_path(struct gw_trans *, - struct gw_dir *); -static const struct got_error *gw_parse_querystring(struct gw_trans *); -static const struct got_error *gw_blame(struct gw_trans *); -static const struct got_error *gw_blob(struct gw_trans *); -static const struct got_error *gw_diff(struct gw_trans *); -static const struct got_error *gw_index(struct gw_trans *); -static const struct got_error *gw_commits(struct gw_trans *); -static const struct got_error *gw_briefs(struct gw_trans *); -static const struct got_error *gw_summary(struct gw_trans *); -static const struct got_error *gw_tree(struct gw_trans *); -static const struct got_error *gw_tag(struct gw_trans *); -static const struct got_error *gw_tags(struct gw_trans *); - -struct gw_query_action { - unsigned int func_id; - const char *func_name; - const struct got_error *(*func_main)(struct gw_trans *); - const char *template; -}; - -enum gw_query_actions { - GW_BLAME, - GW_BLOB, - GW_BRIEFS, - GW_COMMITS, - GW_DIFF, - GW_ERR, - GW_INDEX, - GW_SUMMARY, - GW_TAG, - GW_TAGS, - GW_TREE, -}; - -static const struct gw_query_action gw_query_funcs[] = { - { GW_BLAME, "blame", gw_blame, "gw_tmpl/blame.tmpl" }, - { GW_BLOB, "blob", NULL, NULL }, - { GW_BRIEFS, "briefs", gw_briefs, "gw_tmpl/briefs.tmpl" }, - { GW_COMMITS, "commits", gw_commits, "gw_tmpl/commit.tmpl" }, - { GW_DIFF, "diff", gw_diff, "gw_tmpl/diff.tmpl" }, - { GW_ERR, "error", gw_error, "gw_tmpl/err.tmpl" }, - { GW_INDEX, "index", gw_index, "gw_tmpl/index.tmpl" }, - { GW_SUMMARY, "summary", gw_summary, "gw_tmpl/summry.tmpl" }, - { GW_TAG, "tag", gw_tag, "gw_tmpl/tag.tmpl" }, - { GW_TAGS, "tags", gw_tags, "gw_tmpl/tags.tmpl" }, - { GW_TREE, "tree", gw_tree, "gw_tmpl/tree.tmpl" }, -}; - -static const char * -gw_get_action_name(struct gw_trans *gw_trans) -{ - return gw_query_funcs[gw_trans->action].func_name; -} - -static const struct got_error * -gw_kcgi_error(enum kcgi_err kerr) -{ - if (kerr == KCGI_OK) - return NULL; - - if (kerr == KCGI_EXIT || kerr == KCGI_HUP) - return got_error(GOT_ERR_CANCELLED); - - if (kerr == KCGI_ENOMEM) - return got_error_set_errno(ENOMEM, - kcgi_strerror(kerr)); - - if (kerr == KCGI_ENFILE) - return got_error_set_errno(ENFILE, - kcgi_strerror(kerr)); - - if (kerr == KCGI_EAGAIN) - return got_error_set_errno(EAGAIN, - kcgi_strerror(kerr)); - - if (kerr == KCGI_FORM) - return got_error_msg(GOT_ERR_IO, - kcgi_strerror(kerr)); - - return got_error_from_errno(kcgi_strerror(kerr)); -} - -static const struct got_error * -gw_apply_unveil(const char *repo_path) -{ - const struct got_error *err; - -#ifdef PROFILE - if (unveil("gmon.out", "rwc") != 0) - return got_error_from_errno2("unveil", "gmon.out"); -#endif - if (repo_path && unveil(repo_path, "r") != 0) - return got_error_from_errno2("unveil", repo_path); - - if (unveil(GOT_TMPDIR_STR, "rwc") != 0) - return got_error_from_errno2("unveil", GOT_TMPDIR_STR); - - err = got_privsep_unveil_exec_helpers(); - if (err != NULL) - return err; - - if (unveil(NULL, NULL) != 0) - return got_error_from_errno("unveil"); - - return NULL; -} - -static int -isbinary(const uint8_t *buf, size_t n) -{ - size_t i; - - for (i = 0; i < n; i++) - if (buf[i] == 0) - return 1; - return 0; -} - -static const struct got_error * -gw_blame(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL; - char *age = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - /* check querystring */ - if (gw_trans->repo_file == NULL) { - error = got_error_msg(GOT_ERR_QUERYSTRING, - "file required in querystring"); - goto done; - } - if (gw_trans->commit_id == NULL) { - error = got_error_msg(GOT_ERR_QUERYSTRING, - "commit required in querystring"); - goto done; - } - - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_header_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_header", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_get_time_str(&age, header->committer_time, - TM_LONG); - if (error) - goto done; - error = gw_gen_age_header(gw_trans, age ?age : ""); - if (error) - goto done; - error = gw_gen_commit_msg_header(gw_trans, header->commit_msg); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_output_file_blame(gw_trans, header); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); -done: - gw_free_header(header); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_blob(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL, *err = NULL; - struct gw_header *header = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - /* check querystring */ - if (gw_trans->repo_file == NULL) { - error = got_error_msg(GOT_ERR_QUERYSTRING, - "file required in querystring"); - goto done; - } - if (gw_trans->commit_id == NULL) { - error = got_error_msg(GOT_ERR_QUERYSTRING, - "commit required in querystring"); - goto done; - } - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - - error = gw_output_blob_buf(gw_trans, header); -done: - if (error) { - gw_trans->mime = KMIME_TEXT_PLAIN; - err = gw_display_index(gw_trans); - if (err) { - error = err; - goto errored; - } - kerr = khttp_puts(gw_trans->gw_req, error->msg); - } -errored: - gw_free_header(header); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_diff(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL; - char *age = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "diff_header_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "diff_header", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_gen_diff_header(gw_trans, header->parent_id, - header->commit_id); - if (error) - goto done; - error = gw_gen_commit_header(gw_trans, header->commit_id, - header->refs_str); - if (error) - goto done; - error = gw_gen_tree_header(gw_trans, header->tree_id); - if (error) - goto done; - error = gw_gen_author_header(gw_trans, header->author); - if (error) - goto done; - error = gw_gen_committer_header(gw_trans, header->author); - if (error) - goto done; - error = gw_get_time_str(&age, header->committer_time, - TM_LONG); - if (error) - goto done; - error = gw_gen_age_header(gw_trans, age ?age : ""); - if (error) - goto done; - error = gw_gen_commit_msg_header(gw_trans, header->commit_msg); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "diff", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_output_diff(gw_trans, header); - if (error) - goto done; - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - gw_free_header(header); - free(age); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_index(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_dir *gw_dir = NULL; - char *href_next = NULL, *href_prev = NULL, *href_summary = NULL; - char *href_briefs = NULL, *href_commits = NULL, *href_tree = NULL; - char *href_tags = NULL; - unsigned int prev_disp = 0, next_disp = 1, dir_c = 0; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) { - error = got_error_from_errno("pledge"); - return error; - } -#endif - error = gw_apply_unveil(gw_trans->gw_conf->got_repos_path); - if (error) - return error; - - error = gw_load_got_paths(gw_trans); - if (error) - return error; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_header", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_header_project", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_puts(gw_trans->gw_html_req, "Project"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (gw_trans->gw_conf->got_show_repo_description) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_header_description", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_puts(gw_trans->gw_html_req, "Description"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - if (gw_trans->gw_conf->got_show_repo_owner) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_header_owner", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_puts(gw_trans->gw_html_req, "Owner"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - if (gw_trans->gw_conf->got_show_repo_age) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_header_age", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_puts(gw_trans->gw_html_req, "Last Change"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (TAILQ_EMPTY(&gw_trans->gw_dirs)) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_printf(gw_trans->gw_html_req, - "No repositories found in %s", - gw_trans->gw_conf->got_repos_path); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - return error; - } - - TAILQ_FOREACH(gw_dir, &gw_trans->gw_dirs, entry) - dir_c++; - - TAILQ_FOREACH(gw_dir, &gw_trans->gw_dirs, entry) { - if (gw_trans->page > 0 && (gw_trans->page * - gw_trans->gw_conf->got_max_repos_display) > prev_disp) { - prev_disp++; - continue; - } - - prev_disp++; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_dir->name, "action", "summary", NULL); - if (href_summary == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "index_project", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_summary, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, gw_dir->name); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - if (gw_trans->gw_conf->got_show_repo_description) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "index_project_description", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_dir->description ? gw_dir->description : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - if (gw_trans->gw_conf->got_show_repo_owner) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "index_project_owner", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_dir->owner ? gw_dir->owner : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - if (gw_trans->gw_conf->got_show_repo_age) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "index_project_age", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_dir->age ? gw_dir->age : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "navs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "navs", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_summary, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "summary"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_briefs = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_dir->name, "action", "briefs", NULL); - if (href_briefs == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_briefs, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "commit briefs"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_commits = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_dir->name, "action", "commits", NULL); - if (href_commits == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_commits, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "commits"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_tags = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_dir->name, "action", "tags", NULL); - if (href_tags == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_tags, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "tags"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_dir->name, "action", "tree", NULL); - if (href_tree == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_tree, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "tree"); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_closeelem(gw_trans->gw_html_req, 4); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - free(href_summary); - href_summary = NULL; - free(href_briefs); - href_briefs = NULL; - free(href_commits); - href_commits = NULL; - free(href_tags); - href_tags = NULL; - free(href_tree); - href_tree = NULL; - - if (gw_trans->gw_conf->got_max_repos_display == 0) - continue; - - if ((next_disp == gw_trans->gw_conf->got_max_repos_display) || - ((gw_trans->gw_conf->got_max_repos_display > 0) && - (gw_trans->page > 0) && - (next_disp == gw_trans->gw_conf->got_max_repos_display || - prev_disp == gw_trans->repos_total))) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "np_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_prev", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - } - - if ((gw_trans->gw_conf->got_max_repos_display > 0) && - (gw_trans->page > 0) && - (next_disp == gw_trans->gw_conf->got_max_repos_display || - prev_disp == gw_trans->repos_total)) { - href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "page", - KATTRX_INT, (int64_t)(gw_trans->page - 1), NULL); - if (href_prev == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_prev, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Previous"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (gw_trans->gw_conf->got_max_repos_display > 0 && - next_disp == gw_trans->gw_conf->got_max_repos_display && - dir_c != (gw_trans->page + 1) * - gw_trans->gw_conf->got_max_repos_display) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_next", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - href_next = khttp_urlpartx(NULL, NULL, "gotweb", "page", - KATTRX_INT, (int64_t)(gw_trans->page + 1), NULL); - if (href_next == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_next, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Next"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - next_disp = 0; - break; - } - - if ((gw_trans->gw_conf->got_max_repos_display > 0) && - (gw_trans->page > 0) && - (next_disp == gw_trans->gw_conf->got_max_repos_display || - prev_disp == gw_trans->repos_total)) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - } - next_disp++; - } -done: - free(href_prev); - free(href_next); - free(href_summary); - free(href_briefs); - free(href_commits); - free(href_tags); - free(href_tree); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_commits(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL, *n_header = NULL; - char *age = NULL, *href_diff = NULL, *href_tree = NULL; - char *href_prev = NULL, *href_next = NULL; - enum kcgi_err kerr = KCGI_OK; - int commit_found = 0; - - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) { - error = got_error_from_errno("pledge"); - goto done; - } -#endif - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - error = gw_get_header(gw_trans, header, - gw_trans->gw_conf->got_max_commits_display); - if (error) - goto done; - - TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) { - if (commit_found == 0 && gw_trans->commit_id != NULL) { - if (strcmp(gw_trans->commit_id, - n_header->commit_id) != 0) - continue; - else - commit_found = 1; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "commits_line_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_gen_commit_header(gw_trans, n_header->commit_id, - n_header->refs_str); - if (error) - goto done; - error = gw_gen_author_header(gw_trans, n_header->author); - if (error) - goto done; - error = gw_gen_committer_header(gw_trans, n_header->author); - if (error) - goto done; - error = gw_get_time_str(&age, n_header->committer_time, - TM_LONG); - if (error) - goto done; - error = gw_gen_age_header(gw_trans, age ?age : ""); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "commit", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khttp_puts(gw_trans->gw_req, n_header->commit_msg); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "diff", "commit", - n_header->commit_id, NULL); - if (href_diff == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_diff, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "diff"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "tree", "commit", - n_header->commit_id, NULL); - if (href_tree == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_tree, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - khtml_puts(gw_trans->gw_html_req, "tree"); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "solid_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - - free(age); - age = NULL; - } - - if (gw_trans->next_id || gw_trans->prev_id) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "np_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_prev", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->prev_id) { - href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page - 1), "action", - KATTRX_STRING, "commits", "commit", KATTRX_STRING, - gw_trans->prev_id ? gw_trans->prev_id : "", NULL); - if (href_prev == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_prev, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Previous"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - if (gw_trans->next_id) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_next", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page + 1), "action", - KATTRX_STRING, "commits", "commit", KATTRX_STRING, - gw_trans->next_id, NULL); - if (href_next == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_next, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Next"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - } -done: - gw_free_header(header); - TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) - gw_free_header(n_header); - free(age); - free(href_next); - free(href_prev); - free(href_diff); - free(href_tree); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_briefs(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL, *n_header = NULL; - char *age = NULL, *href_diff = NULL, *href_tree = NULL; - char *href_prev = NULL, *href_next = NULL; - char *newline, *smallerthan; - enum kcgi_err kerr = KCGI_OK; - int commit_found = 0; - - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) { - error = got_error_from_errno("pledge"); - goto done; - } -#endif - if (gw_trans->action != GW_SUMMARY) { - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - } - - if (gw_trans->action == GW_SUMMARY) - error = gw_get_header(gw_trans, header, D_MAXSLCOMMDISP); - else - error = gw_get_header(gw_trans, header, - gw_trans->gw_conf->got_max_commits_display); - if (error) - goto done; - - TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) { - if (commit_found == 0 && gw_trans->commit_id != NULL) { - if (strcmp(gw_trans->commit_id, - n_header->commit_id) != 0) - continue; - else - commit_found = 1; - } - error = gw_get_time_str(&age, n_header->committer_time, - TM_DIFF); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "briefs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "briefs_age", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, age ? age : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "briefs_author", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - smallerthan = strchr(n_header->author, '<'); - if (smallerthan) - *smallerthan = '\0'; - kerr = khtml_puts(gw_trans->gw_html_req, n_header->author); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "diff", "commit", - n_header->commit_id, NULL); - if (href_diff == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "briefs_log", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - newline = strchr(n_header->commit_msg, '\n'); - if (newline) - *newline = '\0'; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_diff, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, n_header->commit_msg); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - if (n_header->refs_str) { - kerr = khtml_puts(gw_trans->gw_html_req, " "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_SPAN, - KATTR_ID, "refs_str", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, "(%s)", - n_header->refs_str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_diff, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "diff"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "tree", "commit", - n_header->commit_id, NULL); - if (href_tree == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_tree, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - khtml_puts(gw_trans->gw_html_req, "tree"); - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - - free(age); - age = NULL; - free(href_diff); - href_diff = NULL; - free(href_tree); - href_tree = NULL; - } - - if (gw_trans->next_id || gw_trans->prev_id) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "np_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_prev", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->prev_id) { - href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page - 1), "action", - KATTRX_STRING, "briefs", "commit", KATTRX_STRING, - gw_trans->prev_id ? gw_trans->prev_id : "", NULL); - if (href_prev == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_prev, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Previous"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - if (gw_trans->next_id) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_next", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page + 1), "action", - KATTRX_STRING, "briefs", "commit", KATTRX_STRING, - gw_trans->next_id, NULL); - if (href_next == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_next, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Next"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - } -done: - gw_free_header(header); - TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) - gw_free_header(n_header); - free(age); - free(href_next); - free(href_prev); - free(href_diff); - free(href_tree); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_summary(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - char *age = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "summary_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (gw_trans->gw_conf->got_show_repo_description && - gw_trans->gw_dir->description != NULL && - (strcmp(gw_trans->gw_dir->description, "") != 0)) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "description_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Description: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "description", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_trans->gw_dir->description); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->gw_conf->got_show_repo_owner && - gw_trans->gw_dir->owner != NULL && - (strcmp(gw_trans->gw_dir->owner, "") != 0)) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "repo_owner_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Owner: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "repo_owner", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_trans->gw_dir->owner); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->gw_conf->got_show_repo_age) { - error = gw_get_repo_age(&age, gw_trans, gw_trans->gw_dir->path, - NULL, TM_LONG); - if (error) - goto done; - if (age != NULL) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "last_change_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - "Last Change: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "last_change", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, age); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - } - - if (gw_trans->gw_conf->got_show_repo_cloneurl && - gw_trans->gw_dir->url != NULL && - (strcmp(gw_trans->gw_dir->url, "") != 0)) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "cloneurl_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Clone URL: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "cloneurl", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->gw_dir->url); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "briefs_title_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "briefs_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Commit Briefs"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - error = gw_briefs(gw_trans); - if (error) - goto done; - - error = gw_tags(gw_trans); - if (error) - goto done; - - error = gw_output_repo_heads(gw_trans); -done: - free(age); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_tree(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL; - char *tree = NULL, *tree_html = NULL, *tree_html_disp = NULL; - char *age = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tree_header_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tree_header", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_gen_tree_header(gw_trans, header->tree_id); - if (error) - goto done; - error = gw_get_time_str(&age, header->committer_time, - TM_LONG); - if (error) - goto done; - error = gw_gen_age_header(gw_trans, age ?age : ""); - if (error) - goto done; - error = gw_gen_commit_msg_header(gw_trans, header->commit_msg); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tree", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_output_repo_tree(gw_trans, header); - if (error) - goto done; - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - gw_free_header(header); - free(tree_html_disp); - free(tree_html); - free(tree); - free(age); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_tags(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL; - char *href_next = NULL, *href_prev = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", - NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - if (gw_trans->action != GW_SUMMARY) { - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - } - - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - - if (gw_trans->action == GW_SUMMARY) { - gw_trans->next_id = NULL; - error = gw_output_repo_tags(gw_trans, header, - D_MAXSLCOMMDISP, TAGBRIEF); - if (error) - goto done; - } else { - error = gw_output_repo_tags(gw_trans, header, - gw_trans->gw_conf->got_max_commits_display, TAGBRIEF); - if (error) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "np_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_prev", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->prev_id) { - href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page - 1), "action", - KATTRX_STRING, "tags", "commit", KATTRX_STRING, - gw_trans->prev_id ? gw_trans->prev_id : "", NULL); - if (href_prev == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_prev, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Previous"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - if (gw_trans->next_id) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "nav_next", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path", - KATTRX_STRING, gw_trans->repo_name, "page", - KATTRX_INT, (int64_t) (gw_trans->page + 1), "action", - KATTRX_STRING, "tags", "commit", KATTRX_STRING, - gw_trans->next_id, NULL); - if (href_next == NULL) { - error = got_error_from_errno("khttp_urlpartx"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_next, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Next"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - } - - if (gw_trans->next_id || gw_trans->page > 0) { - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - } -done: - gw_free_header(header); - free(href_next); - free(href_prev); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_tag(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct gw_header *header = NULL; - enum kcgi_err kerr = KCGI_OK; - -#ifndef PROFILE - if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", NULL) == -1) - return got_error_from_errno("pledge"); -#endif - if ((header = gw_init_header()) == NULL) - return got_error_from_errno("malloc"); - - error = gw_apply_unveil(gw_trans->gw_dir->path); - if (error) - goto done; - - if (gw_trans->commit_id == NULL) { - error = got_error_msg(GOT_ERR_QUERYSTRING, - "commit required in querystring"); - goto done; - } - - error = gw_get_header(gw_trans, header, 1); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tag_header_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tag_header", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_gen_commit_header(gw_trans, header->commit_id, - header->refs_str); - if (error) - goto done; - error = gw_gen_commit_msg_header(gw_trans, header->commit_msg); - if (error) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tree", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - error = gw_output_repo_tags(gw_trans, header, 1, TAGFULL); - if (error) - goto done; - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - gw_free_header(header); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_load_got_path(struct gw_trans *gw_trans, struct gw_dir *gw_dir) -{ - const struct got_error *error = NULL; - DIR *dt; - char *dir_test; - int opened = 0; - - if (asprintf(&dir_test, "%s/%s/%s", - gw_trans->gw_conf->got_repos_path, gw_dir->name, - GOTWEB_GIT_DIR) == -1) - return got_error_from_errno("asprintf"); - - dt = opendir(dir_test); - if (dt == NULL) { - free(dir_test); - } else { - gw_dir->path = strdup(dir_test); - if (gw_dir->path == NULL) { - opened = 1; - error = got_error_from_errno("strdup"); - goto errored; - } - opened = 1; - goto done; - } - - if (asprintf(&dir_test, "%s/%s/%s", - gw_trans->gw_conf->got_repos_path, gw_dir->name, - GOTWEB_GOT_DIR) == -1) { - dir_test = NULL; - error = got_error_from_errno("asprintf"); - goto errored; - } - - dt = opendir(dir_test); - if (dt == NULL) - free(dir_test); - else { - opened = 1; - error = got_error(GOT_ERR_NOT_GIT_REPO); - goto errored; - } - - if (asprintf(&dir_test, "%s/%s", - gw_trans->gw_conf->got_repos_path, gw_dir->name) == -1) { - error = got_error_from_errno("asprintf"); - dir_test = NULL; - goto errored; - } - - gw_dir->path = strdup(dir_test); - if (gw_dir->path == NULL) { - opened = 1; - error = got_error_from_errno("strdup"); - goto errored; - } - - dt = opendir(dir_test); - if (dt == NULL) { - error = got_error_path(gw_dir->name, GOT_ERR_NOT_GIT_REPO); - goto errored; - } else - opened = 1; -done: - error = gw_get_repo_description(&gw_dir->description, gw_trans, - gw_dir->path); - if (error) - goto errored; - error = gw_get_repo_owner(&gw_dir->owner, gw_trans, gw_dir->path); - if (error) - goto errored; - error = gw_get_repo_age(&gw_dir->age, gw_trans, gw_dir->path, - NULL, TM_DIFF); - if (error) - goto errored; - error = gw_get_clone_url(&gw_dir->url, gw_trans, gw_dir->path); -errored: - free(dir_test); - if (opened) - if (dt && closedir(dt) == -1 && error == NULL) - error = got_error_from_errno("closedir"); - return error; -} - -static const struct got_error * -gw_load_got_paths(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - DIR *d; - struct dirent **sd_dent; - struct gw_dir *gw_dir; - struct stat st; - unsigned int d_cnt, d_i; - - d = opendir(gw_trans->gw_conf->got_repos_path); - if (d == NULL) { - error = got_error_from_errno2("opendir", - gw_trans->gw_conf->got_repos_path); - return error; - } - - d_cnt = scandir(gw_trans->gw_conf->got_repos_path, &sd_dent, NULL, - alphasort); - if (d_cnt == -1) { - error = got_error_from_errno2("scandir", - gw_trans->gw_conf->got_repos_path); - goto done; - } - - for (d_i = 0; d_i < d_cnt; d_i++) { - if (gw_trans->gw_conf->got_max_repos > 0 && - (d_i - 2) == gw_trans->gw_conf->got_max_repos) - break; /* account for parent and self */ - - if (strcmp(sd_dent[d_i]->d_name, ".") == 0 || - strcmp(sd_dent[d_i]->d_name, "..") == 0) - continue; - - error = gw_init_gw_dir(&gw_dir, sd_dent[d_i]->d_name); - if (error) - goto done; - - error = gw_load_got_path(gw_trans, gw_dir); - if (error && error->code == GOT_ERR_NOT_GIT_REPO) { - error = NULL; - continue; - } else if (error && error->code != GOT_ERR_LONELY_PACKIDX) - goto done; - - if (lstat(gw_dir->path, &st) == 0 && S_ISDIR(st.st_mode) && - !got_path_dir_is_empty(gw_dir->path)) { - TAILQ_INSERT_TAIL(&gw_trans->gw_dirs, gw_dir, - entry); - gw_trans->repos_total++; - } - } -done: - if (d && closedir(d) == -1 && error == NULL) - error = got_error_from_errno("closedir"); - return error; -} - -static const struct got_error * -gw_parse_querystring(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct kpair *p; - const struct gw_query_action *action = NULL; - unsigned int i; - - if (gw_trans->gw_req->fieldnmap[0]) { - return got_error(GOT_ERR_QUERYSTRING); - } else if ((p = gw_trans->gw_req->fieldmap[KEY_PATH])) { - /* define gw_trans->repo_path */ - gw_trans->repo_name = p->parsed.s; - - if (asprintf(&gw_trans->repo_path, "%s/%s", - gw_trans->gw_conf->got_repos_path, p->parsed.s) == -1) - return got_error_from_errno("asprintf"); - - /* get action and set function */ - if ((p = gw_trans->gw_req->fieldmap[KEY_ACTION])) { - for (i = 0; i < nitems(gw_query_funcs); i++) { - action = &gw_query_funcs[i]; - if (action->func_name == NULL) - continue; - if (strcmp(action->func_name, - p->parsed.s) == 0) { - gw_trans->action = i; - break; - } - } - } - if (gw_trans->action == -1) { - gw_trans->action = GW_ERR; - gw_trans->error = got_error_msg(GOT_ERR_QUERYSTRING, - p != NULL ? "bad action in querystring" : - "no action in querystring"); - return error; - } - - if ((p = gw_trans->gw_req->fieldmap[KEY_COMMIT_ID])) { - if (asprintf(&gw_trans->commit_id, "%s", - p->parsed.s) == -1) - return got_error_from_errno("asprintf"); - } - - if ((p = gw_trans->gw_req->fieldmap[KEY_FILE])) - gw_trans->repo_file = p->parsed.s; - - if ((p = gw_trans->gw_req->fieldmap[KEY_FOLDER])) { - if (asprintf(&gw_trans->repo_folder, "%s", - p->parsed.s) == -1) - return got_error_from_errno("asprintf"); - } - - if ((p = gw_trans->gw_req->fieldmap[KEY_PREV_ID])) { - if (asprintf(&gw_trans->prev_id, "%s", - p->parsed.s) == -1) - return got_error_from_errno("asprintf"); - } - - if ((p = gw_trans->gw_req->fieldmap[KEY_HEADREF])) - gw_trans->headref = p->parsed.s; - - error = gw_init_gw_dir(&gw_trans->gw_dir, gw_trans->repo_name); - if (error) - return error; - - gw_trans->error = gw_load_got_path(gw_trans, gw_trans->gw_dir); - } else - gw_trans->action = GW_INDEX; - - if ((p = gw_trans->gw_req->fieldmap[KEY_PAGE])) - gw_trans->page = p->parsed.i; - - return error; -} - -static const struct got_error * -gw_init_gw_dir(struct gw_dir **gw_dir, const char *dir) -{ - const struct got_error *error; - - *gw_dir = malloc(sizeof(**gw_dir)); - if (*gw_dir == NULL) - return got_error_from_errno("malloc"); - - if (asprintf(&(*gw_dir)->name, "%s", dir) == -1) { - error = got_error_from_errno("asprintf"); - free(*gw_dir); - *gw_dir = NULL; - return error; - } - - return NULL; -} - -static const struct got_error * -gw_display_open(struct gw_trans *gw_trans, enum khttp code, enum kmime mime) -{ - enum kcgi_err kerr = KCGI_OK; - - kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_ALLOW], "GET"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_STATUS], "%s", - khttps[code]); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_CONTENT_TYPE], "%s", - kmimetypes[mime]); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khttp_head(gw_trans->gw_req, "X-Content-Type-Options", - "nosniff"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khttp_head(gw_trans->gw_req, "X-Frame-Options", "DENY"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - kerr = khttp_head(gw_trans->gw_req, "X-XSS-Protection", - "1; mode=block"); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (gw_trans->mime == KMIME_APP_OCTET_STREAM) { - kerr = khttp_head(gw_trans->gw_req, - kresps[KRESP_CONTENT_DISPOSITION], - "attachment; filename=%s", gw_trans->repo_file); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - } - - kerr = khttp_body(gw_trans->gw_req); - return gw_kcgi_error(kerr); -} - -static const struct got_error * -gw_display_index(struct gw_trans *gw_trans) -{ - const struct got_error *error; - enum kcgi_err kerr = KCGI_OK; - - /* catch early querystring errors */ - if (gw_trans->error) - gw_trans->action = GW_ERR; - - error = gw_display_open(gw_trans, KHTTP_200, gw_trans->mime); - if (error) - return error; - - kerr = khtml_open(gw_trans->gw_html_req, gw_trans->gw_req, 0); - if (kerr != KCGI_OK) - return gw_kcgi_error(kerr); - - if (gw_trans->action != GW_BLOB) { - kerr = khttp_template(gw_trans->gw_req, gw_trans->gw_tmpl, - gw_query_funcs[gw_trans->action].template); - if (kerr != KCGI_OK) { - khtml_close(gw_trans->gw_html_req); - return gw_kcgi_error(kerr); - } - } - - return gw_kcgi_error(khtml_close(gw_trans->gw_html_req)); -} - -static const struct got_error * -gw_error(struct gw_trans *gw_trans) -{ - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->error->msg); - - return gw_kcgi_error(kerr); -} - -static int -gw_template(size_t key, void *arg) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - struct gw_trans *gw_trans = arg; - char *ati = NULL, *fic32 = NULL, *fic16 = NULL; - char *swm = NULL, *spt = NULL, *css = NULL, *logo = NULL; - - if (asprintf(&ati, "%s%s", gw_trans->gw_conf->got_www_path, - "/apple-touch-icon.png") == -1) - goto err; - if (asprintf(&fic32, "%s%s", gw_trans->gw_conf->got_www_path, - "/favicon-32x32.png") == -1) - goto err; - if (asprintf(&fic16, "%s%s", gw_trans->gw_conf->got_www_path, - "/favicon-16x16.png") == -1) - goto err; - if (asprintf(&swm, "%s%s", gw_trans->gw_conf->got_www_path, - "/site.webmanifest") == -1) - goto err; - if (asprintf(&spt, "%s%s", gw_trans->gw_conf->got_www_path, - "/safari-pinned-tab.svg") == -1) - goto err; - if (asprintf(&css, "%s%s", gw_trans->gw_conf->got_www_path, - "/gotweb.css") == -1) - goto err; - if (asprintf(&logo, "%s%s%s", gw_trans->gw_conf->got_www_path, - gw_trans->gw_conf->got_www_path ? "/" : "", - gw_trans->gw_conf->got_logo) == -1) - goto err; - - switch (key) { - case (TEMPL_HEAD): - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META, - KATTR_NAME, "viewport", - KATTR_CONTENT, "initial-scale=.75, user-scalable=yes", - KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META, - KATTR_CHARSET, "utf-8", - KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META, - KATTR_NAME, "msapplication-TileColor", - KATTR_CONTENT, "#da532c", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META, - KATTR_NAME, "theme-color", - KATTR_CONTENT, "#ffffff", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "apple-touch-icon", KATTR_SIZES, "180x180", - KATTR_HREF, ati, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "icon", KATTR_TYPE, "image/png", KATTR_SIZES, - "32x32", KATTR_HREF, fic32, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "icon", KATTR_TYPE, "image/png", KATTR_SIZES, - "16x16", KATTR_HREF, fic16, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "manifest", KATTR_HREF, swm, - KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "mask-icon", KATTR_HREF, - spt, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK, - KATTR_REL, "stylesheet", KATTR_TYPE, "text/css", - KATTR_HREF, css, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - break; - case(TEMPL_HEADER): - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "got_link", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, gw_trans->gw_conf->got_logo_url, - KATTR_TARGET, "_sotd", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_IMG, - KATTR_SRC, logo, KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - return 0; - break; - case (TEMPL_SITEPATH): - error = gw_output_site_link(gw_trans); - if (error) - return 0; - break; - case(TEMPL_TITLE): - if (gw_trans->gw_conf->got_site_name != NULL) { - kerr = khtml_puts(gw_trans->gw_html_req, - gw_trans->gw_conf->got_site_name); - if (kerr != KCGI_OK) - return 0; - } - break; - case (TEMPL_SEARCH): - break; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "search", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_FORM, - KATTR_METHOD, "POST", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_INPUT, KATTR_ID, - "got-search", KATTR_NAME, "got-search", KATTR_SIZE, "15", - KATTR_MAXLENGTH, "50", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_BUTTON, - KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_puts(gw_trans->gw_html_req, "Search"); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 4); - if (kerr != KCGI_OK) - return 0; - break; - case(TEMPL_SITEOWNER): - if (gw_trans->gw_conf->got_site_owner != NULL && - gw_trans->gw_conf->got_show_site_owner) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "site_owner_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "site_owner", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_trans->gw_conf->got_site_owner); - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - return 0; - } - break; - case(TEMPL_CONTENT): - error = gw_query_funcs[gw_trans->action].func_main(gw_trans); - if (error) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tmpl_err", KATTR__MAX); - if (kerr != KCGI_OK) - return 0; - kerr = khttp_printf(gw_trans->gw_req, "Error: %s", - error->msg); - if (kerr != KCGI_OK) - return 0; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - return 0; - } - break; - default: - return 0; - } - free(ati); - free(fic32); - free(fic16); - free(swm); - free(spt); - free(css); - free(logo); - return 1; -err: - free(ati); - free(fic32); - free(fic16); - free(swm); - free(spt); - free(css); - free(logo); - return 0; -} - -static const struct got_error * -gw_gen_commit_header(struct gw_trans *gw_trans, char *str1, char *str2) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_commit_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Commit: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_commit", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, "%s ", str1); - if (kerr != KCGI_OK) - goto done; - if (str2 != NULL) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_SPAN, - KATTR_ID, "refs_str", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, "(%s)", str2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_diff_header(struct gw_trans *gw_trans, char *str1, char *str2) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_diff_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Diff: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_diff", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - if (str1 != NULL) { - kerr = khtml_puts(gw_trans->gw_html_req, str1); - if (kerr != KCGI_OK) - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_BR, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, str2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_age_header(struct gw_trans *gw_trans, const char *str) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_age_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Date: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_age", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_author_header(struct gw_trans *gw_trans, const char *str) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_author_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Author: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_author", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_committer_header(struct gw_trans *gw_trans, const char *str) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_committer_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Committer: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_committer", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_commit_msg_header(struct gw_trans *gw_trans, char *str) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_commit_msg_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Message: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_commit_msg", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khttp_puts(gw_trans->gw_req, str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_gen_tree_header(struct gw_trans *gw_trans, char *str) -{ - const struct got_error *error = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_tree_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Tree: "); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "header_tree", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, str); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); -done: - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_get_repo_description(char **description, struct gw_trans *gw_trans, - char *dir) -{ - const struct got_error *error = NULL; - FILE *f = NULL; - char *d_file = NULL; - unsigned int len; - size_t n; - - *description = NULL; - if (gw_trans->gw_conf->got_show_repo_description == 0) - return NULL; - - if (asprintf(&d_file, "%s/description", dir) == -1) - return got_error_from_errno("asprintf"); - - f = fopen(d_file, "re"); - if (f == NULL) { - if (errno == ENOENT || errno == EACCES) - return NULL; - error = got_error_from_errno2("fopen", d_file); - goto done; - } - - if (fseek(f, 0, SEEK_END) == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - len = ftell(f); - if (len == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - if (fseek(f, 0, SEEK_SET) == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - *description = calloc(len + 1, sizeof(**description)); - if (*description == NULL) { - error = got_error_from_errno("calloc"); - goto done; - } - - n = fread(*description, 1, len, f); - if (n == 0 && ferror(f)) - error = got_ferror(f, GOT_ERR_IO); -done: - if (f != NULL && fclose(f) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - free(d_file); - return error; -} - -static const struct got_error * -gw_get_time_str(char **repo_age, time_t committer_time, int ref_tm) -{ - struct tm tm; - time_t diff_time; - const char *years = "years ago", *months = "months ago"; - const char *weeks = "weeks ago", *days = "days ago", *hours = "hours ago"; - const char *minutes = "minutes ago", *seconds = "seconds ago"; - const char *now = "right now"; - const char *s; - char datebuf[29]; - - *repo_age = NULL; - - switch (ref_tm) { - case TM_DIFF: - diff_time = time(NULL) - committer_time; - if (diff_time > 60 * 60 * 24 * 365 * 2) { - if (asprintf(repo_age, "%lld %s", - (diff_time / 60 / 60 / 24 / 365), years) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 60 * 60 * 24 * (365 / 12) * 2) { - if (asprintf(repo_age, "%lld %s", - (diff_time / 60 / 60 / 24 / (365 / 12)), - months) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 60 * 60 * 24 * 7 * 2) { - if (asprintf(repo_age, "%lld %s", - (diff_time / 60 / 60 / 24 / 7), weeks) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 60 * 60 * 24 * 2) { - if (asprintf(repo_age, "%lld %s", - (diff_time / 60 / 60 / 24), days) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 60 * 60 * 2) { - if (asprintf(repo_age, "%lld %s", - (diff_time / 60 / 60), hours) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 60 * 2) { - if (asprintf(repo_age, "%lld %s", (diff_time / 60), - minutes) == -1) - return got_error_from_errno("asprintf"); - } else if (diff_time > 2) { - if (asprintf(repo_age, "%lld %s", diff_time, - seconds) == -1) - return got_error_from_errno("asprintf"); - } else { - if (asprintf(repo_age, "%s", now) == -1) - return got_error_from_errno("asprintf"); - } - break; - case TM_LONG: - if (gmtime_r(&committer_time, &tm) == NULL) - return got_error_from_errno("gmtime_r"); - - s = asctime_r(&tm, datebuf); - if (s == NULL) - return got_error_from_errno("asctime_r"); - - if (asprintf(repo_age, "%s UTC", datebuf) == -1) - return got_error_from_errno("asprintf"); - break; - } - return NULL; -} - -static const struct got_error * -gw_get_repo_age(char **repo_age, struct gw_trans *gw_trans, char *dir, - const char *refname, int ref_tm) -{ - const struct got_error *error = NULL; - struct got_repository *repo = NULL; - struct got_commit_object *commit = NULL; - struct got_reflist_head refs; - struct got_reflist_entry *re; - time_t committer_time = 0, cmp_time = 0; - - *repo_age = NULL; - TAILQ_INIT(&refs); - - if (gw_trans->gw_conf->got_show_repo_age == 0) - return NULL; - - if (gw_trans->repo) - repo = gw_trans->repo; - else { - error = got_repo_open(&repo, dir, NULL, gw_trans->pack_fds); - if (error) - return error; - } - - error = got_ref_list(&refs, repo, "refs/heads", - got_ref_cmp_by_name, NULL); - if (error) - goto done; - - /* - * Find the youngest branch tip in the repository, or the age of - * the a specific branch tip if a name was provided by the caller. - */ - TAILQ_FOREACH(re, &refs, entry) { - struct got_object_id *id = NULL; - - if (refname && strcmp(got_ref_get_name(re->ref), refname) != 0) - continue; - - error = got_ref_resolve(&id, repo, re->ref); - if (error) - goto done; - - error = got_object_open_as_commit(&commit, repo, id); - free(id); - if (error) - goto done; - - committer_time = - got_object_commit_get_committer_time(commit); - got_object_commit_close(commit); - if (cmp_time < committer_time) - cmp_time = committer_time; - - if (refname) - break; - } - - if (cmp_time != 0) { - committer_time = cmp_time; - error = gw_get_time_str(repo_age, committer_time, ref_tm); - } -done: - got_ref_list_free(&refs); - if (gw_trans->repo == NULL) { - const struct got_error *close_err = got_repo_close(repo); - if (error == NULL) - error = close_err; - } - return error; -} - -static const struct got_error * -gw_output_diff(struct gw_trans *gw_trans, struct gw_header *header) -{ - const struct got_error *error; - FILE *f = NULL, *f1 = NULL, *f2 = NULL; - int fd1 = -1, fd2 = -1; - struct got_object_id *id1 = NULL, *id2 = NULL; - char *label1 = NULL, *label2 = NULL, *line = NULL; - int obj_type; - size_t linesize = 0; - ssize_t linelen; - enum kcgi_err kerr = KCGI_OK; - - f = got_opentemp(); - if (f == NULL) - return NULL; - - f1 = got_opentemp(); - if (f1 == NULL) { - error = got_error_from_errno("got_opentemp"); - goto done; - } - - f2 = got_opentemp(); - if (f2 == NULL) { - error = got_error_from_errno("got_opentemp"); - goto done; - } - - fd1 = got_opentempfd(); - if (fd1 == -1) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - - fd2 = got_opentempfd(); - if (fd2 == -1) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - - if (header->parent_id != NULL && - strncmp(header->parent_id, "/dev/null", 9) != 0) { - error = got_repo_match_object_id(&id1, &label1, - header->parent_id, GOT_OBJ_TYPE_ANY, - &header->refs, gw_trans->repo); - if (error) - goto done; - } - - error = got_repo_match_object_id(&id2, &label2, - header->commit_id, GOT_OBJ_TYPE_ANY, &header->refs, - gw_trans->repo); - if (error) - goto done; - - error = got_object_get_type(&obj_type, gw_trans->repo, id2); - if (error) - goto done; - switch (obj_type) { - case GOT_OBJ_TYPE_BLOB: - error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, - fd1, fd2, id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE, - 3, 0, 0, gw_trans->repo, f); - break; - case GOT_OBJ_TYPE_TREE: - error = got_diff_objects_as_trees(NULL, NULL, f1, f2, - fd1, fd2, id1, id2, NULL, "", "", - GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, gw_trans->repo, f); - break; - case GOT_OBJ_TYPE_COMMIT: - error = got_diff_objects_as_commits(NULL, NULL, f1, f2, - fd1, fd2, id1, id2, NULL, GOT_DIFF_ALGORITHM_PATIENCE, - 3, 0, 0, gw_trans->repo, f); - break; - default: - error = got_error(GOT_ERR_OBJ_TYPE); - } - if (error) - goto done; - - if (fseek(f, 0, SEEK_SET) == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - - while ((linelen = getline(&line, &linesize, f)) != -1) { - error = gw_colordiff_line(gw_trans, line); - if (error) - goto done; - /* XXX: KHTML_PRETTY breaks this */ - kerr = khtml_puts(gw_trans->gw_html_req, line); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - } - if (linelen == -1 && ferror(f)) - error = got_error_from_errno("getline"); -done: - if (f && fclose(f) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - if (f1 && fclose(f1) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - if (f2 && fclose(f2) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - if (fd1 != -1 && close(fd1) == -1 && error == NULL) - error = got_error_from_errno("close"); - if (fd2 != -1 && close(fd2) == -1 && error == NULL) - error = got_error_from_errno("close"); - free(line); - free(label1); - free(label2); - free(id1); - free(id2); - - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_get_repo_owner(char **owner, struct gw_trans *gw_trans, char *dir) -{ - const struct got_error *error = NULL, *close_err; - struct got_repository *repo; - const char *gitconfig_owner; - - *owner = NULL; - - if (gw_trans->gw_conf->got_show_repo_owner == 0) - return NULL; - - error = got_repo_open(&repo, dir, NULL, gw_trans->pack_fds); - if (error) - return error; - - gitconfig_owner = got_repo_get_gitconfig_owner(repo); - if (gitconfig_owner) { - *owner = strdup(gitconfig_owner); - if (*owner == NULL) - error = got_error_from_errno("strdup"); - } - close_err = got_repo_close(repo); - if (error == NULL) - error = close_err; - return error; -} - -static const struct got_error * -gw_get_clone_url(char **url, struct gw_trans *gw_trans, char *dir) -{ - const struct got_error *error = NULL; - FILE *f; - char *d_file = NULL; - unsigned int len; - size_t n; - - *url = NULL; - - if (asprintf(&d_file, "%s/cloneurl", dir) == -1) - return got_error_from_errno("asprintf"); - - f = fopen(d_file, "re"); - if (f == NULL) { - if (errno != ENOENT && errno != EACCES) - error = got_error_from_errno2("fopen", d_file); - goto done; - } - - if (fseek(f, 0, SEEK_END) == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - len = ftell(f); - if (len == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - if (fseek(f, 0, SEEK_SET) == -1) { - error = got_ferror(f, GOT_ERR_IO); - goto done; - } - - *url = calloc(len + 1, sizeof(**url)); - if (*url == NULL) { - error = got_error_from_errno("calloc"); - goto done; - } - - n = fread(*url, 1, len, f); - if (n == 0 && ferror(f)) - error = got_ferror(f, GOT_ERR_IO); -done: - if (f && fclose(f) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - free(d_file); - return NULL; -} - -static const struct got_error * -gw_output_repo_tags(struct gw_trans *gw_trans, struct gw_header *header, - int limit, int tag_type) -{ - const struct got_error *error = NULL; - struct got_reflist_head refs; - struct got_reflist_entry *re; - char *age = NULL; - char *id_str = NULL, *newline, *href_commits = NULL; - char *tag_commit0 = NULL, *href_tag = NULL, *href_briefs = NULL; - struct got_tag_object *tag = NULL; - enum kcgi_err kerr = KCGI_OK; - int summary_header_displayed = 0, chk_next = 0; - int tag_count = 0, commit_found = 0, c_cnt = 0; - - TAILQ_INIT(&refs); - - error = got_ref_list(&refs, gw_trans->repo, "refs/tags", - got_ref_cmp_tags, gw_trans->repo); - if (error) - goto done; - - TAILQ_FOREACH(re, &refs, entry) { - const char *refname; - const char *tagger; - const char *tag_commit; - time_t tagger_time; - struct got_object_id *id; - struct got_commit_object *commit = NULL; - - refname = got_ref_get_name(re->ref); - if (strncmp(refname, "refs/tags/", 10) != 0) - continue; - refname += 10; - - error = got_ref_resolve(&id, gw_trans->repo, re->ref); - if (error) - goto done; - - error = got_object_open_as_tag(&tag, gw_trans->repo, id); - if (error) { - if (error->code != GOT_ERR_OBJ_TYPE) { - free(id); - goto done; - } - /* "lightweight" tag */ - error = got_object_open_as_commit(&commit, - gw_trans->repo, id); - if (error) { - free(id); - goto done; - } - tagger = got_object_commit_get_committer(commit); - tagger_time = - got_object_commit_get_committer_time(commit); - error = got_object_id_str(&id_str, id); - free(id); - } else { - free(id); - tagger = got_object_tag_get_tagger(tag); - tagger_time = got_object_tag_get_tagger_time(tag); - error = got_object_id_str(&id_str, - got_object_tag_get_object_id(tag)); - } - if (error) - goto done; - - if (tag_type == TAGFULL && strncmp(id_str, header->commit_id, - strlen(id_str)) != 0) - continue; - - if (tag_type == TAGBRIEF && gw_trans->commit_id && - commit_found == 0 && strncmp(id_str, gw_trans->commit_id, - strlen(id_str)) != 0) - continue; - else - commit_found = 1; - - tag_count++; - - if (chk_next) { - gw_trans->next_id = strdup(id_str); - if (gw_trans->next_id == NULL) - error = got_error_from_errno("strdup"); - goto prev; - } - - if (commit) { - error = got_object_commit_get_logmsg(&tag_commit0, - commit); - if (error) - goto done; - got_object_commit_close(commit); - } else { - tag_commit0 = strdup(got_object_tag_get_message(tag)); - if (tag_commit0 == NULL) { - error = got_error_from_errno("strdup"); - goto done; - } - } - - tag_commit = tag_commit0; - while (*tag_commit == '\n') - tag_commit++; - - switch (tag_type) { - case TAGBRIEF: - newline = strchr(tag_commit, '\n'); - if (newline) - *newline = '\0'; - - if (summary_header_displayed == 0) { - kerr = khtml_attr(gw_trans->gw_html_req, - KELEM_DIV, KATTR_ID, - "summary_tags_title_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, - KELEM_DIV, KATTR_ID, - "summary_tags_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - "Tags"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, - 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, - KELEM_DIV, KATTR_ID, - "summary_tags_content", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - summary_header_displayed = 1; - } - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_age", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_get_time_str(&age, tagger_time, TM_DIFF); - if (error) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - age ? age : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, refname); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_name", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - href_tag = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "tag", "commit", - id_str, NULL); - if (href_tag == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_tag, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, tag_commit); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "navs", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_tag, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "tag"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_briefs = khttp_urlpart(NULL, NULL, "gotweb", - "path", gw_trans->repo_name, "action", "briefs", - "commit", id_str, NULL); - if (href_briefs == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_briefs, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - "commit briefs"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_commits = khttp_urlpart(NULL, NULL, "gotweb", - "path", gw_trans->repo_name, "action", "commits", - "commit", id_str, NULL); - if (href_commits == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_commits, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "commits"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - break; - case TAGFULL: - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_info_date_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Tag Date:"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_info_date", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - error = gw_get_time_str(&age, tagger_time, TM_LONG); - if (error) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - age ? age : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_info_tagger_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Tagger:"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_info_date", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, tagger); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tag_info", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khttp_puts(gw_trans->gw_req, tag_commit); - if (kerr != KCGI_OK) - goto done; - break; - default: - break; - } - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - if (limit && --limit == 0) - chk_next = 1; - - if (tag) - got_object_tag_close(tag); - tag = NULL; - free(id_str); - id_str = NULL; - free(age); - age = NULL; - free(tag_commit0); - tag_commit0 = NULL; - free(href_tag); - href_tag = NULL; - free(href_briefs); - href_briefs = NULL; - free(href_commits); - href_commits = NULL; - } - if (tag_count == 0) { - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "summary_tags_title_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "summary_tags_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Tags"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "summary_tags_content", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "tags_info", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khttp_puts(gw_trans->gw_req, - "There are no tags for this repo."); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - goto done; - } -prev: - commit_found = 0; - TAILQ_FOREACH_REVERSE(re, &refs, got_reflist_head, entry) { - const char *refname; - struct got_object_id *id; - struct got_commit_object *commit = NULL; - - refname = got_ref_get_name(re->ref); - if (strncmp(refname, "refs/tags/", 10) != 0) - continue; - refname += 10; - - error = got_ref_resolve(&id, gw_trans->repo, re->ref); - if (error) - goto done; - - error = got_object_open_as_tag(&tag, gw_trans->repo, id); - if (error) { - if (error->code != GOT_ERR_OBJ_TYPE) { - free(id); - goto done; - } - /* "lightweight" tag */ - error = got_object_open_as_commit(&commit, - gw_trans->repo, id); - if (error) { - free(id); - goto done; - } - error = got_object_id_str(&id_str, id); - free(id); - } else { - free(id); - error = got_object_id_str(&id_str, - got_object_tag_get_object_id(tag)); - } - if (error) - goto done; - - if (tag_type == TAGFULL && strncmp(id_str, header->commit_id, - strlen(id_str)) != 0) - continue; - - if (commit_found == 0 && tag_type == TAGBRIEF && - gw_trans->commit_id != NULL && - strncmp(id_str, gw_trans->commit_id, strlen(id_str)) != 0) - continue; - else - commit_found = 1; - - if (gw_trans->commit_id != NULL && - strcmp(id_str, gw_trans->commit_id) != 0 && - (re == TAILQ_FIRST(&refs) || - c_cnt == gw_trans->gw_conf->got_max_commits_display)) { - gw_trans->prev_id = strdup(id_str); - if (gw_trans->prev_id == NULL) { - error = got_error_from_errno("strdup"); - goto done; - } - break; - } - c_cnt++; - } -done: - if (tag) - got_object_tag_close(tag); - free(id_str); - free(age); - free(tag_commit0); - free(href_tag); - free(href_briefs); - free(href_commits); - got_ref_list_free(&refs); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static void -gw_free_header(struct gw_header *header) -{ - free(header->path); - free(header->author); - free(header->committer); - free(header->refs_str); - free(header->commit_id); - free(header->parent_id); - free(header->tree_id); - free(header->commit_msg); -} - -static struct gw_header * -gw_init_header() -{ - struct gw_header *header; - - header = malloc(sizeof(*header)); - if (header == NULL) - return NULL; - - header->path = NULL; - TAILQ_INIT(&header->refs); - - header->refs_str = NULL; - header->commit_id = NULL; - header->committer = NULL; - header->author = NULL; - header->parent_id = NULL; - header->tree_id = NULL; - header->commit_msg = NULL; - - return header; -} - -static const struct got_error * -gw_get_commits(struct gw_trans * gw_trans, struct gw_header *header, - int limit, struct got_object_id *iter_start_id) -{ - const struct got_error *error = NULL; - struct got_commit_graph *graph = NULL; - struct got_commit_object *commit = NULL; - int chk_next = 0, chk_multi = 0, c_cnt = 0, commit_found = 0; - struct gw_header *t_header = NULL; - - error = got_commit_graph_open(&graph, header->path, 0); - if (error) - return error; - - error = got_commit_graph_iter_start(graph, iter_start_id, - gw_trans->repo, NULL, NULL); - if (error) - goto err; - - for (;;) { - struct got_object_id id; - - error = got_commit_graph_iter_next(&id, graph, gw_trans->repo, - NULL, NULL); - if (error) { - if (error->code == GOT_ERR_ITER_COMPLETED) - error = NULL; - goto done; - } - - error = got_object_open_as_commit(&commit, gw_trans->repo, &id); - if (error) - goto err; - if (limit == 1 && chk_multi == 0 && - gw_trans->gw_conf->got_max_commits_display != 1) { - error = gw_get_commit(gw_trans, header, commit, &id); - if (error) - goto err; - commit_found = 1; - } else { - chk_multi = 1; - struct gw_header *n_header = NULL; - if ((n_header = gw_init_header()) == NULL) { - error = got_error_from_errno("malloc"); - goto err; - } - TAILQ_INSERT_TAIL(&gw_trans->gw_headers, n_header, - entry); - error = got_ref_list(&n_header->refs, gw_trans->repo, - NULL, got_ref_cmp_by_name, NULL); - if (error) - goto err; - - error = gw_get_commit(gw_trans, n_header, commit, &id); - if (error) - goto err; - got_ref_list_free(&n_header->refs); - - if (gw_trans->commit_id != NULL) { - if (strcmp(gw_trans->commit_id, - n_header->commit_id) == 0) - commit_found = 1; - } else - commit_found = 1; - - /* - * check for one more commit before breaking, - * so we know whether to navigate through gw_briefs - * gw_commits and gw_summary - */ - if (chk_next && (gw_trans->action == GW_BRIEFS || - gw_trans->action == GW_COMMITS || - gw_trans->action == GW_SUMMARY)) { - gw_trans->next_id = strdup(n_header->commit_id); - if (gw_trans->next_id == NULL) - error = got_error_from_errno("strdup"); - TAILQ_REMOVE(&gw_trans->gw_headers, n_header, - entry); - goto done; - } - - } - if (commit_found == 1 && (error || (limit && --limit == 0))) { - if (chk_multi == 0) - break; - chk_next = 1; - } - } -done: - if (gw_trans->prev_id == NULL && gw_trans->commit_id != NULL && - (gw_trans->action == GW_BRIEFS || gw_trans->action == GW_COMMITS)) { - commit_found = 0; - TAILQ_FOREACH_REVERSE(t_header, &gw_trans->gw_headers, - headers, entry) { - if (commit_found == 0 && - strcmp(gw_trans->commit_id, - t_header->commit_id) != 0) - continue; - else - commit_found = 1; - if (gw_trans->commit_id != NULL && - strcmp(gw_trans->commit_id, - t_header->commit_id) != 0 && - (c_cnt == gw_trans->gw_conf->got_max_commits_display - || t_header == - TAILQ_FIRST(&gw_trans->gw_headers))) { - gw_trans->prev_id = strdup(t_header->commit_id); - if (gw_trans->prev_id == NULL) - error = got_error_from_errno("strdup"); - break; - } - c_cnt++; - } - } -err: - if (commit != NULL) - got_object_commit_close(commit); - if (graph) - got_commit_graph_close(graph); - return error; -} - -static const struct got_error * -gw_get_commit(struct gw_trans *gw_trans, struct gw_header *header, - struct got_commit_object *commit, struct got_object_id *id) -{ - const struct got_error *error = NULL; - struct got_reflist_entry *re; - struct got_object_id *id2 = NULL; - struct got_object_qid *parent_id; - char *commit_msg = NULL, *commit_msg0; - - /*print commit*/ - TAILQ_FOREACH(re, &header->refs, entry) { - char *s; - const char *name; - struct got_tag_object *tag = NULL; - struct got_object_id *ref_id; - int cmp; - - if (got_ref_is_symbolic(re->ref)) - continue; - - name = got_ref_get_name(re->ref); - if (strncmp(name, "refs/", 5) == 0) - name += 5; - if (strncmp(name, "got/", 4) == 0) - continue; - if (strncmp(name, "heads/", 6) == 0) - name += 6; - if (strncmp(name, "remotes/", 8) == 0) { - name += 8; - s = strstr(name, "/" GOT_REF_HEAD); - if (s != NULL && s[strlen(s)] == '\0') - continue; - } - error = got_ref_resolve(&ref_id, gw_trans->repo, re->ref); - if (error) - return error; - if (strncmp(name, "tags/", 5) == 0) { - error = got_object_open_as_tag(&tag, gw_trans->repo, - ref_id); - if (error) { - if (error->code != GOT_ERR_OBJ_TYPE) { - free(ref_id); - continue; - } - /* - * Ref points at something other - * than a tag. - */ - error = NULL; - tag = NULL; - } - } - cmp = got_object_id_cmp(tag ? - got_object_tag_get_object_id(tag) : ref_id, id); - free(ref_id); - if (tag) - got_object_tag_close(tag); - if (cmp != 0) - continue; - s = header->refs_str; - if (asprintf(&header->refs_str, "%s%s%s", s ? s : "", - s ? ", " : "", name) == -1) { - error = got_error_from_errno("asprintf"); - free(s); - header->refs_str = NULL; - return error; - } - free(s); - } - - error = got_object_id_str(&header->commit_id, id); - if (error) - return error; - - error = got_object_id_str(&header->tree_id, - got_object_commit_get_tree_id(commit)); - if (error) - return error; - - if (gw_trans->action == GW_DIFF) { - parent_id = STAILQ_FIRST( - got_object_commit_get_parent_ids(commit)); - if (parent_id != NULL) { - id2 = got_object_id_dup(&parent_id->id); - free (parent_id); - error = got_object_id_str(&header->parent_id, id2); - if (error) - return error; - free(id2); - } else { - header->parent_id = strdup("/dev/null"); - if (header->parent_id == NULL) { - error = got_error_from_errno("strdup"); - return error; - } - } - } - - header->committer_time = - got_object_commit_get_committer_time(commit); - - header->author = - strdup(got_object_commit_get_author(commit)); - if (header->author == NULL) { - error = got_error_from_errno("strdup"); - return error; - } - header->committer = - strdup(got_object_commit_get_committer(commit)); - if (header->committer == NULL) { - error = got_error_from_errno("strdup"); - return error; - } - error = got_object_commit_get_logmsg(&commit_msg0, commit); - if (error) - return error; - - commit_msg = commit_msg0; - while (*commit_msg == '\n') - commit_msg++; - - header->commit_msg = strdup(commit_msg); - if (header->commit_msg == NULL) - error = got_error_from_errno("strdup"); - free(commit_msg0); - return error; -} - -static const struct got_error * -gw_get_header(struct gw_trans *gw_trans, struct gw_header *header, int limit) -{ - const struct got_error *error = NULL; - char *in_repo_path = NULL; - struct got_object_id *id = NULL; - struct got_reference *ref; - - error = got_repo_open(&gw_trans->repo, gw_trans->repo_path, NULL, - gw_trans->pack_fds); - if (error) - return error; - - if (gw_trans->commit_id == NULL || gw_trans->action == GW_COMMITS || - gw_trans->action == GW_BRIEFS || gw_trans->action == GW_SUMMARY || - gw_trans->action == GW_TAGS) { - error = got_ref_open(&ref, gw_trans->repo, - gw_trans->headref, 0); - if (error) - return error; - - error = got_ref_resolve(&id, gw_trans->repo, ref); - got_ref_close(ref); - if (error) - return error; - } else { - error = got_ref_open(&ref, gw_trans->repo, - gw_trans->commit_id, 0); - if (error == NULL) { - int obj_type; - error = got_ref_resolve(&id, gw_trans->repo, ref); - got_ref_close(ref); - if (error) - return error; - error = got_object_get_type(&obj_type, gw_trans->repo, - id); - if (error) - goto done; - if (obj_type == GOT_OBJ_TYPE_TAG) { - struct got_tag_object *tag; - error = got_object_open_as_tag(&tag, - gw_trans->repo, id); - if (error) - goto done; - if (got_object_tag_get_object_type(tag) != - GOT_OBJ_TYPE_COMMIT) { - got_object_tag_close(tag); - error = got_error(GOT_ERR_OBJ_TYPE); - goto done; - } - free(id); - id = got_object_id_dup( - got_object_tag_get_object_id(tag)); - if (id == NULL) - error = got_error_from_errno( - "got_object_id_dup"); - got_object_tag_close(tag); - if (error) - goto done; - } else if (obj_type != GOT_OBJ_TYPE_COMMIT) { - error = got_error(GOT_ERR_OBJ_TYPE); - goto done; - } - } - error = got_repo_match_object_id_prefix(&id, - gw_trans->commit_id, GOT_OBJ_TYPE_COMMIT, - gw_trans->repo); - if (error) - goto done; - } - - error = got_repo_map_path(&in_repo_path, gw_trans->repo, - gw_trans->repo_path); - if (error) - goto done; - - if (in_repo_path) { - header->path = strdup(in_repo_path); - if (header->path == NULL) { - error = got_error_from_errno("strdup"); - goto done; - } - } - - error = got_ref_list(&header->refs, gw_trans->repo, NULL, - got_ref_cmp_by_name, NULL); - if (error) - goto done; - - error = gw_get_commits(gw_trans, header, limit, id); -done: - free(id); - free(in_repo_path); - return error; -} - -struct blame_line { - int annotated; - char *id_str; - char *committer; - char datebuf[11]; /* YYYY-MM-DD + NUL */ -}; - -struct gw_blame_cb_args { - struct blame_line *lines; - int nlines; - int nlines_prec; - int lineno_cur; - off_t *line_offsets; - FILE *f; - struct got_repository *repo; - struct gw_trans *gw_trans; -}; - -static const struct got_error * -gw_blame_cb(void *arg, int nlines, int lineno, - struct got_commit_object *commit, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct gw_blame_cb_args *a = arg; - struct blame_line *bline; - char *line = NULL; - size_t linesize = 0; - off_t offset; - struct tm tm; - time_t committer_time; - enum kcgi_err kerr = KCGI_OK; - - if (nlines != a->nlines || - (lineno != -1 && lineno < 1) || lineno > a->nlines) - return got_error(GOT_ERR_RANGE); - - if (lineno == -1) - return NULL; /* no change in this commit */ - - /* Annotate this line. */ - bline = &a->lines[lineno - 1]; - if (bline->annotated) - return NULL; - err = got_object_id_str(&bline->id_str, id); - if (err) - return err; - - bline->committer = strdup(got_object_commit_get_committer(commit)); - if (bline->committer == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - - committer_time = got_object_commit_get_committer_time(commit); - if (gmtime_r(&committer_time, &tm) == NULL) - return got_error_from_errno("gmtime_r"); - if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d", - &tm) == 0) { - err = got_error(GOT_ERR_NO_SPACE); - goto done; - } - bline->annotated = 1; - - /* Print lines annotated so far. */ - bline = &a->lines[a->lineno_cur - 1]; - if (!bline->annotated) - goto done; - - offset = a->line_offsets[a->lineno_cur - 1]; - if (fseeko(a->f, offset, SEEK_SET) == -1) { - err = got_error_from_errno("fseeko"); - goto done; - } - - while (a->lineno_cur <= a->nlines && bline->annotated) { - char *smallerthan, *at, *nl, *committer; - char *href_diff = NULL; - size_t len; - - if (getline(&line, &linesize, a->f) == -1) { - if (ferror(a->f)) - err = got_error_from_errno("getline"); - break; - } - - committer = bline->committer; - smallerthan = strchr(committer, '<'); - if (smallerthan && smallerthan[1] != '\0') - committer = smallerthan + 1; - at = strchr(committer, '@'); - if (at) - *at = '\0'; - len = strlen(committer); - if (len >= 9) - committer[8] = '\0'; - - nl = strchr(line, '\n'); - if (nl) - *nl = '\0'; - - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_number", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_printf(a->gw_trans->gw_html_req, "%.*d", - a->nlines_prec, a->lineno_cur); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto err; - - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_hash", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - - href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path", - a->gw_trans->repo_name, "action", "diff", "commit", - bline->id_str, NULL); - if (href_diff == NULL) { - err = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_diff, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(a->gw_trans->gw_html_req, "%.8s", - bline->id_str); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto err; - - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_date", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_puts(a->gw_trans->gw_html_req, bline->datebuf); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto err; - - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_author", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_puts(a->gw_trans->gw_html_req, committer); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto err; - - kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "blame_code", KATTR__MAX); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_puts(a->gw_trans->gw_html_req, line); - if (kerr != KCGI_OK) - goto err; - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto err; - - kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto err; - - a->lineno_cur++; - bline = &a->lines[a->lineno_cur - 1]; -err: - free(href_diff); - } -done: - free(line); - if (err == NULL && kerr != KCGI_OK) - err = gw_kcgi_error(kerr); - return err; -} - -static const struct got_error * -gw_output_file_blame(struct gw_trans *gw_trans, struct gw_header *header) -{ - const struct got_error *error = NULL; - struct got_object_id *obj_id = NULL; - struct got_object_id *commit_id = NULL; - struct got_commit_object *commit = NULL; - struct got_blob_object *blob = NULL; - char *path = NULL, *in_repo_path = NULL; - struct gw_blame_cb_args bca; - int i, obj_type, fd1 = -1, fd2 = -1, fd3 = -1; - off_t filesize; - FILE *f1 = NULL, *f2 = NULL; - - fd1 = got_opentempfd(); - if (fd1 == -1) - return got_error_from_errno("got_opentempfd"); - fd2 = got_opentempfd(); - if (fd2 == -1) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - fd3 = got_opentempfd(); - if (fd3 == -1) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - - memset(&bca, 0, sizeof(bca)); - - if (asprintf(&path, "%s%s%s", - gw_trans->repo_folder ? gw_trans->repo_folder : "", - gw_trans->repo_folder ? "/" : "", - gw_trans->repo_file) == -1) { - error = got_error_from_errno("asprintf"); - goto done; - } - - error = got_repo_map_path(&in_repo_path, gw_trans->repo, path); - if (error) - goto done; - - error = got_repo_match_object_id(&commit_id, NULL, gw_trans->commit_id, - GOT_OBJ_TYPE_COMMIT, &header->refs, gw_trans->repo); - if (error) - goto done; - - error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id); - if (error) - goto done; - - error = got_object_id_by_path(&obj_id, gw_trans->repo, commit, - in_repo_path); - if (error) - goto done; - - if (obj_id == NULL) { - error = got_error(GOT_ERR_NO_OBJ); - goto done; - } - - error = got_object_get_type(&obj_type, gw_trans->repo, obj_id); - if (error) - goto done; - - if (obj_type != GOT_OBJ_TYPE_BLOB) { - error = got_error(GOT_ERR_OBJ_TYPE); - goto done; - } - - error = got_object_open_as_blob(&blob, gw_trans->repo, obj_id, 8192, - fd1); - if (error) - goto done; - - bca.f = got_opentemp(); - if (bca.f == NULL) { - error = got_error_from_errno("got_opentemp"); - goto done; - } - error = got_object_blob_dump_to_file(&filesize, &bca.nlines, - &bca.line_offsets, bca.f, blob); - if (error || bca.nlines == 0) - goto done; - - /* Don't include \n at EOF in the blame line count. */ - if (bca.line_offsets[bca.nlines - 1] == filesize) - bca.nlines--; - - bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); - if (bca.lines == NULL) { - error = got_error_from_errno("calloc"); - goto done; - } - bca.lineno_cur = 1; - bca.nlines_prec = 0; - i = bca.nlines; - while (i > 0) { - i /= 10; - bca.nlines_prec++; - } - bca.repo = gw_trans->repo; - bca.gw_trans = gw_trans; - - fd1 = got_opentempfd(); - if (fd1 == -1) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - - f1 = got_opentemp(); - if (f1 == NULL) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - f2 = got_opentemp(); - if (f2 == NULL) { - error = got_error_from_errno("got_opentempfd"); - goto done; - } - - error = got_blame(in_repo_path, commit_id, gw_trans->repo, - GOT_DIFF_ALGORITHM_PATIENCE, gw_blame_cb, &bca, NULL, NULL, - fd2, fd3, f1, f2); -done: - free(in_repo_path); - free(commit_id); - free(obj_id); - free(path); - - if (fd1 != -1 && close(fd1) == -1 && error == NULL) - error = got_error_from_errno("close"); - if (fd2 != -1 && close(fd2) == -1 && error == NULL) - error = got_error_from_errno("close"); - if (fd3 != -1 && close(fd3) == -1 && error == NULL) - error = got_error_from_errno("close"); - if (f1 && fclose(f1) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - if (f2 && fclose(f2) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - - if (blob) { - free(bca.line_offsets); - for (i = 0; i < bca.nlines; i++) { - struct blame_line *bline = &bca.lines[i]; - free(bline->id_str); - free(bline->committer); - } - free(bca.lines); - if (bca.f && fclose(bca.f) == EOF && error == NULL) - error = got_error_from_errno("fclose"); - } - if (blob) - got_object_blob_close(blob); - if (commit) - got_object_commit_close(commit); - return error; -} - -static const struct got_error * -gw_output_blob_buf(struct gw_trans *gw_trans, struct gw_header *header) -{ - const struct got_error *error = NULL; - struct got_object_id *obj_id = NULL; - struct got_object_id *commit_id = NULL; - struct got_commit_object *commit = NULL; - struct got_blob_object *blob = NULL; - char *path = NULL, *in_repo_path = NULL; - int obj_type, set_mime = 0, fd = -1; - size_t len, hdrlen; - const uint8_t *buf; - enum kcgi_err kerr = KCGI_OK; - - fd = got_opentempfd(); - if (fd == -1) - return got_error_from_errno("got_opentempfd"); - - if (asprintf(&path, "%s%s%s", - gw_trans->repo_folder ? gw_trans->repo_folder : "", - gw_trans->repo_folder ? "/" : "", - gw_trans->repo_file) == -1) { - error = got_error_from_errno("asprintf"); - goto done; - } - - error = got_repo_map_path(&in_repo_path, gw_trans->repo, path); - if (error) - goto done; - - error = got_repo_match_object_id(&commit_id, NULL, gw_trans->commit_id, - GOT_OBJ_TYPE_COMMIT, &header->refs, gw_trans->repo); - if (error) - goto done; - - error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id); - if (error) - goto done; - - error = got_object_id_by_path(&obj_id, gw_trans->repo, commit, - in_repo_path); - if (error) - goto done; - - if (obj_id == NULL) { - error = got_error(GOT_ERR_NO_OBJ); - goto done; - } - - error = got_object_get_type(&obj_type, gw_trans->repo, obj_id); - if (error) - goto done; - - if (obj_type != GOT_OBJ_TYPE_BLOB) { - error = got_error(GOT_ERR_OBJ_TYPE); - goto done; - } - - error = got_object_open_as_blob(&blob, gw_trans->repo, obj_id, 8192, - fd); - if (error) - goto done; - - hdrlen = got_object_blob_get_hdrlen(blob); - do { - error = got_object_blob_read_block(&len, blob); - if (error) - goto done; - buf = got_object_blob_get_read_buf(blob); - - /* - * Skip blob object header first time around, - * which also contains a zero byte. - */ - buf += hdrlen; - if (set_mime == 0) { - if (isbinary(buf, len - hdrlen)) - gw_trans->mime = KMIME_APP_OCTET_STREAM; - else - gw_trans->mime = KMIME_TEXT_PLAIN; - set_mime = 1; - error = gw_display_index(gw_trans); - if (error) - goto done; - } - kerr = khttp_write(gw_trans->gw_req, buf, len - hdrlen); - if (kerr != KCGI_OK) - goto done; - hdrlen = 0; - } while (len != 0); -done: - free(in_repo_path); - free(commit_id); - free(obj_id); - free(path); - if (fd != -1 && close(fd) == -1 && error == NULL) - error = got_error_from_errno("close"); - if (blob) - got_object_blob_close(blob); - if (commit) - got_object_commit_close(commit); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_output_repo_tree(struct gw_trans *gw_trans, struct gw_header *header) -{ - const struct got_error *error = NULL; - struct got_object_id *tree_id = NULL, *commit_id = NULL; - struct got_tree_object *tree = NULL; - struct got_commit_object *commit = NULL; - char *path = NULL, *in_repo_path = NULL; - char *id_str = NULL; - char *build_folder = NULL; - char *href_blob = NULL, *href_blame = NULL; - const char *class = NULL; - int nentries, i, class_flip = 0; - enum kcgi_err kerr = KCGI_OK; - - if (gw_trans->repo_folder != NULL) { - path = strdup(gw_trans->repo_folder); - if (path == NULL) { - error = got_error_from_errno("strdup"); - goto done; - } - } else { - error = got_repo_map_path(&in_repo_path, gw_trans->repo, - gw_trans->repo_path); - if (error) - goto done; - free(path); - path = in_repo_path; - } - - if (gw_trans->commit_id == NULL) { - struct got_reference *head_ref; - error = got_ref_open(&head_ref, gw_trans->repo, - gw_trans->headref, 0); - if (error) - goto done; - error = got_ref_resolve(&commit_id, gw_trans->repo, head_ref); - if (error) - goto done; - got_ref_close(head_ref); - /* - * gw_trans->commit_id was not parsed from the querystring - * we hit this code path from gw_index, where we don't know the - * commit values for the tree link yet, so set - * gw_trans->commit_id here to continue further into the tree - */ - error = got_object_id_str(&gw_trans->commit_id, commit_id); - if (error) - goto done; - - } else { - error = got_repo_match_object_id(&commit_id, NULL, - gw_trans->commit_id, GOT_OBJ_TYPE_COMMIT, &header->refs, - gw_trans->repo); - if (error) - goto done; - } - - error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id); - if (error) - goto done; - - error = got_object_id_by_path(&tree_id, gw_trans->repo, commit, - path); - if (error) - goto done; - - error = got_object_open_as_tree(&tree, gw_trans->repo, tree_id); - if (error) - goto done; - - nentries = got_object_tree_get_nentries(tree); - for (i = 0; i < nentries; i++) { - struct got_tree_entry *te; - const char *modestr = ""; - mode_t mode; - - te = got_object_tree_get_entry(tree, i); - - error = got_object_id_str(&id_str, got_tree_entry_get_id(te)); - if (error) - goto done; - - mode = got_tree_entry_get_mode(te); - if (got_object_tree_entry_is_submodule(te)) - modestr = "$"; - else if (S_ISLNK(mode)) - modestr = "@"; - else if (S_ISDIR(mode)) - modestr = "/"; - else if (mode & S_IXUSR) - modestr = "*"; - - if (class_flip == 0) { - class = "back_lightgray"; - class_flip = 1; - } else { - class = "back_white"; - class_flip = 0; - } - - if (S_ISDIR(mode)) { - if (asprintf(&build_folder, "%s/%s", - gw_trans->repo_folder ? gw_trans->repo_folder : "", - got_tree_entry_get_name(te)) == -1) { - error = got_error_from_errno("asprintf"); - goto done; - } - - href_blob = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", - gw_get_action_name(gw_trans), "commit", - gw_trans->commit_id, "folder", build_folder, NULL); - if (href_blob == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_line", KATTR_CLASS, class, - KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_blob, KATTR_CLASS, - "diff_directory", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, "%s%s", - got_tree_entry_get_name(te), modestr); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_line_blank", KATTR_CLASS, class, - KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_entity(gw_trans->gw_html_req, - KENTITY_nbsp); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - } else { - href_blob = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "blob", "commit", - gw_trans->commit_id, "file", - got_tree_entry_get_name(te), "folder", - gw_trans->repo_folder ? gw_trans->repo_folder : "", - NULL); - if (href_blob == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - href_blame = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "blame", "commit", - gw_trans->commit_id, "file", - got_tree_entry_get_name(te), "folder", - gw_trans->repo_folder ? gw_trans->repo_folder : "", - NULL); - if (href_blame == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_line", KATTR_CLASS, class, - KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_blob, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, "%s%s", - got_tree_entry_get_name(te), modestr); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "tree_line_navs", KATTR_CLASS, class, - KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_blob, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "blob"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, - KATTR_HREF, href_blame, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "blame"); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - } - free(id_str); - id_str = NULL; - free(href_blob); - href_blob = NULL; - free(build_folder); - build_folder = NULL; - } -done: - if (tree) - got_object_tree_close(tree); - if (commit) - got_object_commit_close(commit); - free(id_str); - free(href_blob); - free(href_blame); - free(in_repo_path); - free(tree_id); - free(build_folder); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_output_repo_heads(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - struct got_reflist_head refs; - struct got_reflist_entry *re; - char *age = NULL, *href_summary = NULL, *href_briefs = NULL; - char *href_commits = NULL; - enum kcgi_err kerr = KCGI_OK; - - TAILQ_INIT(&refs); - - error = got_ref_list(&refs, gw_trans->repo, "refs/heads", - got_ref_cmp_by_name, NULL); - if (error) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "summary_heads_title_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "summary_heads_title", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "Heads"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "summary_heads_content", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - TAILQ_FOREACH(re, &refs, entry) { - const char *refname; - - if (got_ref_is_symbolic(re->ref)) - continue; - - refname = got_ref_get_name(re->ref); - if (strncmp(refname, "refs/heads/", 11) != 0) - continue; - - error = gw_get_repo_age(&age, gw_trans, gw_trans->gw_dir->path, - refname, TM_DIFF); - if (error) - goto done; - - if (strncmp(refname, "refs/heads/", 11) == 0) - refname += 11; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "heads_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "heads_age", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, age ? age : ""); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "heads_space", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_entity(gw_trans->gw_html_req, KENTITY_nbsp); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, - KATTR_ID, "head", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "summary", "headref", - refname, NULL); - if (href_summary == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_summary, KATTR__MAX); - kerr = khtml_puts(gw_trans->gw_html_req, refname); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "navs_wrapper", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "navs", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_summary, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "summary"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_briefs = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "briefs", "headref", - refname, NULL); - if (href_briefs == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_briefs, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "commit briefs"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_puts(gw_trans->gw_html_req, " | "); - if (kerr != KCGI_OK) - goto done; - - href_commits = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "commits", "headref", - refname, NULL); - if (href_commits == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_commits, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, "commits"); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 3); - if (kerr != KCGI_OK) - goto done; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "dotted_line", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 2); - if (kerr != KCGI_OK) - goto done; - free(href_summary); - href_summary = NULL; - free(href_briefs); - href_briefs = NULL; - free(href_commits); - href_commits = NULL; - } -done: - got_ref_list_free(&refs); - free(href_summary); - free(href_briefs); - free(href_commits); - return error; -} - -static const struct got_error * -gw_output_site_link(struct gw_trans *gw_trans) -{ - const struct got_error *error = NULL; - char *href_summary = NULL; - enum kcgi_err kerr = KCGI_OK; - - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "site_link", KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, GOTWEB, - KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, - gw_trans->gw_conf->got_site_link); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - - if (gw_trans->repo_name != NULL) { - kerr = khtml_puts(gw_trans->gw_html_req, " / "); - if (kerr != KCGI_OK) - goto done; - - href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path", - gw_trans->repo_name, "action", "summary", NULL); - if (href_summary == NULL) { - error = got_error_from_errno("khttp_urlpart"); - goto done; - } - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, - href_summary, KATTR__MAX); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->repo_name); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; - kerr = khtml_printf(gw_trans->gw_html_req, " / %s", - gw_get_action_name(gw_trans)); - if (kerr != KCGI_OK) - goto done; - } - - kerr = khtml_closeelem(gw_trans->gw_html_req, 1); - if (kerr != KCGI_OK) - goto done; -done: - free(href_summary); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -static const struct got_error * -gw_colordiff_line(struct gw_trans *gw_trans, char *buf) -{ - const struct got_error *error = NULL; - const char *color = NULL; - enum kcgi_err kerr = KCGI_OK; - - if (strncmp(buf, "-", 1) == 0) - color = "diff_minus"; - else if (strncmp(buf, "+", 1) == 0) - color = "diff_plus"; - else if (strncmp(buf, "@@", 2) == 0) - color = "diff_chunk_header"; - else if (strncmp(buf, "@@", 2) == 0) - color = "diff_chunk_header"; - else if (strncmp(buf, "commit +", 8) == 0) - color = "diff_meta"; - else if (strncmp(buf, "commit -", 8) == 0) - color = "diff_meta"; - else if (strncmp(buf, "blob +", 6) == 0) - color = "diff_meta"; - else if (strncmp(buf, "blob -", 6) == 0) - color = "diff_meta"; - else if (strncmp(buf, "file +", 6) == 0) - color = "diff_meta"; - else if (strncmp(buf, "file -", 6) == 0) - color = "diff_meta"; - else if (strncmp(buf, "from:", 5) == 0) - color = "diff_author"; - else if (strncmp(buf, "via:", 4) == 0) - color = "diff_author"; - else if (strncmp(buf, "date:", 5) == 0) - color = "diff_date"; - kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID, - "diff_line", KATTR_CLASS, color ? color : "", KATTR__MAX); - if (error == NULL && kerr != KCGI_OK) - error = gw_kcgi_error(kerr); - return error; -} - -int -main(int argc, char *argv[]) -{ - const struct got_error *error = NULL, *error2 = NULL; - struct gw_trans *gw_trans; - struct gw_dir *dir = NULL, *tdir; - const char *page = "index"; - enum kcgi_err kerr = KCGI_OK; - - if ((gw_trans = malloc(sizeof(struct gw_trans))) == NULL) - errx(1, "malloc"); - - if ((gw_trans->gw_req = malloc(sizeof(struct kreq))) == NULL) - errx(1, "malloc"); - - if ((gw_trans->gw_html_req = malloc(sizeof(struct khtmlreq))) == NULL) - errx(1, "malloc"); - - if ((gw_trans->gw_tmpl = malloc(sizeof(struct ktemplate))) == NULL) - errx(1, "malloc"); - - kerr = khttp_parse(gw_trans->gw_req, gw_keys, KEY__ZMAX, &page, 1, 0); - if (kerr != KCGI_OK) { - error = gw_kcgi_error(kerr); - goto done; - } - - TAILQ_INIT(&gw_trans->gw_dirs); - TAILQ_INIT(&gw_trans->gw_headers); - - gw_trans->action = -1; - gw_trans->page = 0; - gw_trans->repos_total = 0; - gw_trans->repo_path = NULL; - gw_trans->commit_id = NULL; - gw_trans->next_id = NULL; - gw_trans->prev_id = NULL; - gw_trans->headref = GOT_REF_HEAD; - gw_trans->mime = KMIME_TEXT_HTML; - gw_trans->gw_tmpl->key = gw_templs; - gw_trans->gw_tmpl->keysz = TEMPL__MAX; - gw_trans->gw_tmpl->arg = gw_trans; - gw_trans->gw_tmpl->cb = gw_template; - - error = got_repo_pack_fds_open(&gw_trans->pack_fds); - if (error != NULL) - goto done; - - error = parse_gotweb_config(&gw_trans->gw_conf, GOTWEB_CONF); - if (error) - goto done; - - error = gw_parse_querystring(gw_trans); - if (error) - goto done; - - if (gw_trans->repo) { - const struct got_error *close_err; - close_err = got_repo_close(gw_trans->repo); - if (error == NULL) - error = close_err; - } - if (gw_trans->action == GW_BLOB) - error = gw_blob(gw_trans); - else - error = gw_display_index(gw_trans); -done: - if (error) { - gw_trans->error = error; - gw_trans->action = GW_ERR; - error2 = gw_display_open(gw_trans, KHTTP_200, gw_trans->mime); - if (error2) - goto cleanup; /* we can't display an error page */ - kerr = khtml_open(gw_trans->gw_html_req, gw_trans->gw_req, 0); - if (kerr != KCGI_OK) - goto cleanup; /* we can't display an error page */ - kerr = khttp_template(gw_trans->gw_req, gw_trans->gw_tmpl, - gw_query_funcs[gw_trans->action].template); - if (kerr != KCGI_OK) { - khtml_close(gw_trans->gw_html_req); - goto cleanup; /* we can't display an error page */ - } - } - -cleanup: - if (gw_trans->pack_fds) { - const struct got_error *pack_err = - got_repo_pack_fds_close(gw_trans->pack_fds); - if (error == NULL) - error = pack_err; - gw_trans->pack_fds = NULL; - } - free(gw_trans->gw_conf->got_repos_path); - free(gw_trans->gw_conf->got_www_path); - free(gw_trans->gw_conf->got_site_name); - free(gw_trans->gw_conf->got_site_owner); - free(gw_trans->gw_conf->got_site_link); - free(gw_trans->gw_conf->got_logo); - free(gw_trans->gw_conf->got_logo_url); - free(gw_trans->gw_conf); - free(gw_trans->commit_id); - free(gw_trans->next_id); - free(gw_trans->prev_id); - free(gw_trans->repo_path); - TAILQ_FOREACH_SAFE(dir, &gw_trans->gw_dirs, entry, tdir) { - free(dir->name); - free(dir->description); - free(dir->age); - free(dir->url); - free(dir->path); - free(dir); - } - - khttp_free(gw_trans->gw_req); - return 0; -} blob - b9dd2b0786d5a06a4c43e97bf29aeab25650d68d file + /dev/null --- gotweb/gotweb.conf.5 +++ /dev/null @@ -1,135 +0,0 @@ -.\" -.\" Copyright (c) 2020 Tracey Emery <tracey@traceyemery.net> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate$ -.Dt GOTWEB.CONF 5 -.Os -.Sh NAME -.Nm gotweb.conf -.Nd gotweb configuration file -.Sh DESCRIPTION -.Nm -is the run-time configuration file for -.Xr gotweb 8 . -.Pp -The file format is line-based, with one configuration directive per line. -Any lines beginning with a -.Sq # -are treated as comments and ignored. -.Pp -Paths mentioned in -.Nm -must be relative to -.Pa /var/www , -the -.Xr chroot 2 -environment of -.Xr httpd 8 . -.Sh GLOBAL CONFIGURATION -The available configuration directives are as follows: -.Bl -tag -width Ds -.It Ic got_max_commits_display Ar number -Set the maximum amount of commits displayed per page. -.It Ic got_logo Ar path -Set the path to an image file containing a logo to be displayed. -.It Ic got_logo_url Ar url -Set a hyperlink for the logo. -.It Ic got_max_repos Ar number -Set the maximum amount of repositories -.Xr gotweb 8 -will work with. -.It Ic got_max_repos_display Ar number -Set the maximum amount of repositories displayed on the index screen. -.It Ic got_show_repo_age Ar on | off -Toggle display of last repository modification date. -.It Ic got_show_repo_cloneurl Ar on | off -Toggle display of clone URLs for a repository. -This requires the creation of a -.Pa cloneurl -file inside the repository which contains one URL per line. -.It Ic got_show_repo_description Ar on | off -Toggle display of the repository description. -The -.Pa description -file in the repository should be updated with an appropriate description. -.It Ic got_repos_path Ar path -Set the path to the directory which contains Git repositories that -.Xr gotweb 8 -should publish. -.It Ic got_show_repo_owner Ar on | off -Set whether to display the repository owner. -Displaying the owner requires owner information to be added to the -.Pa config -file in the repository. -.Xr gotweb 8 -will parse owner information from either a [gotweb] or a [gitweb] section. -For example: -.Bd -literal -offset indent -[gotweb] -owner = "Your Name" -.Ed -.It Ic got_site_link Ar string -Set the displayed site link name for the index page. -.It Ic got_site_name Ar string -Set the displayed site name title. -.It Ic got_site_owner Ar string -Set the displayed site owner. -.It Ic got_show_site_owner Ar on | off -Toggle display of the site owner. -.It Ic got_www_path Ar string -Set the public gotweb httpd path. -.El -.Sh FILES -.Bl -tag -width Ds -compact -.It Pa /var/www/etc/gotweb.conf -Location of the -.Nm -configuration file. -.El -.Sh EXAMPLES -These are the currently configurable items for -.Xr gotweb 8 -with their default values. -.Bd -literal -offset indent - -# -# gotweb options -# all paths relative to /var/www (httpd chroot jail) -# - -got_repos_path "/got/public" -got_www_path "/gotweb" - -#got_max_repos 100 -#got_max_repos_display 25 -got_max_commits_display 50 - -got_site_name "my public repos" -got_site_owner "Got Owner" -got_site_link "repos" - -got_logo "got.png" -got_logo_url "https://gameoftrees.org" - -# on by default -#got_show_site_owner off -#got_show_repo_owner off -#got_show_repo_age false -#got_show_repo_description no -#got_show_repo_cloneurl off -.Ed -.Sh SEE ALSO -.Xr got 1 , -.Xr gotweb 8 blob - aa311d40d3fa8a2632f5b8c4acd5c1e933cc8c49 file + /dev/null --- gotweb/gotweb.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net> - * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef GOTWEB_H -#define GOTWEB_H - -#include <stdbool.h> - -#define GOTWEB_CONF "/etc/gotweb.conf" -#define GOTWEB_TMPL_DIR "/cgi-bin/gw_tmpl" -#define GOTWEB "/cgi-bin/gotweb/gotweb" - -#define GOTWEB_GOT_DIR ".got" -#define GOTWEB_GIT_DIR ".git" - -#define D_GOTWWW "/gotweb" -#define D_GOTPATH "/got/public" -#define D_SITENAME "Gotweb" -#define D_SITEOWNER "Got Owner" -#define D_SITELINK "Repos" -#define D_GOTLOGO "got.png" -#define D_GOTURL "https://gameoftrees.org" - -#define D_SHOWROWNER true -#define D_SHOWSOWNER true -#define D_SHOWAGE true -#define D_SHOWDESC true -#define D_SHOWURL true -#define D_MAXREPO 0 -#define D_MAXREPODISP 25 -#define D_MAXSLCOMMDISP 10 -#define D_MAXCOMMITDISP 25 - -#define BUFFER_SIZE 2048 - -struct gotweb_config { - char *got_repos_path; - char *got_www_path; - char *got_site_name; - char *got_site_owner; - char *got_site_link; - char *got_logo; - char *got_logo_url; - - size_t got_max_repos; - size_t got_max_repos_display; - size_t got_max_commits_display; - - bool got_show_site_owner; - bool got_show_repo_owner; - bool got_show_repo_age; - bool got_show_repo_description; - bool got_show_repo_cloneurl; -}; - -/* - * Parse gotweb config file, if it exists - * Load gotweb_config struct - */ -const struct got_error* parse_gotweb_config(struct gotweb_config **, - const char *); - -#endif /* GOTWEB_H */ blob - 5fd34708bd3654bc05060446ff5d55557747cfd3 file + /dev/null --- gotweb/libexec/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIR = got-read-blob got-read-commit got-read-object got-read-tree \ - got-read-tag got-read-pack got-read-gitconfig got-read-gotconfig - -.include <bsd.subdir.mk> blob - 85bee26728643214f5d4570f003572ac1fc36d05 file + /dev/null --- gotweb/libexec/Makefile.inc +++ /dev/null @@ -1,11 +0,0 @@ -.include "../Makefile.inc" - -realinstall: - if [ ! -d ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/. ]; then \ - ${INSTALL} -d -o root -g daemon -m 755 \ - ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}; \ - fi - ${INSTALL} ${INSTALL_COPY} -o root -g daemon -m 755 ${PROG} \ - ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/${PROG} - -NOMAN = Yes blob - 58d428b99c43b2fba80028b6233bcd4ff6c7e4a4 file + /dev/null --- gotweb/libexec/got-read-blob/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-blob -SRCS= got-read-blob.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-blob - -.include <bsd.prog.mk> blob - 669332cc8be5487a26cc868b873f782c7e351623 file + /dev/null --- gotweb/libexec/got-read-commit/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-commit -SRCS= got-read-commit.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-commit - -.include <bsd.prog.mk> blob - d81d4666fc3206a3008ddfc673992c5ec3265bd9 file + /dev/null --- gotweb/libexec/got-read-gitconfig/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-gitconfig -SRCS= got-read-gitconfig.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c gitconfig.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gitconfig - -.include <bsd.prog.mk> blob - abc9574b7efb93c971c76b3576970c8c19ba0e14 file + /dev/null --- gotweb/libexec/got-read-gotconfig/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-gotconfig -SRCS= got-read-gotconfig.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c parse.y pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib \ - -I${.CURDIR}/../../../libexec/got-read-gotconfig -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gotconfig - -.include <bsd.prog.mk> blob - 1c3afaf56bad757cf3c8b9574bc12521adbda7bb file + /dev/null --- gotweb/libexec/got-read-object/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-object -SRCS= got-read-object.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-object - -.include <bsd.prog.mk> blob - 9c1bf08b6d1c6cea526cdb38361ef89dfce5bc32 file + /dev/null --- gotweb/libexec/got-read-pack/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-pack -SRCS= got-read-pack.c delta.c error.c inflate.c object_cache.c \ - object_idset.c object_parse.c opentemp.c pack.c path.c \ - privsep.c sha1.c delta_cache.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-pack - -.include <bsd.prog.mk> blob - 450ee15c54e4904304143c4129f1adf9fd085073 file + /dev/null --- gotweb/libexec/got-read-tag/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-tag -SRCS= got-read-tag.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tag - -.include <bsd.prog.mk> blob - 20c0a23b3bf5a858afe4cd8a8e2d57c5194dd074 file + /dev/null --- gotweb/libexec/got-read-tree/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.include "../../../got-version.mk" -.include "../Makefile.inc" - -PROG= got-read-tree -SRCS= got-read-tree.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pollfd.c - -CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib -LDADD = -lutil -lz -DPADD = ${LIBZ} ${LIBUTIL} -LDSTATIC = ${STATIC} - -.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tree - -.include <bsd.prog.mk> blob - e96fe3c7b230722b5e7bd852896389d4d473c7d1 file + /dev/null --- gotweb/parse.y +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Tracey Emery <tracey@openbsd.org> - * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> - * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> - * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. - * Copyright (c) 2001 Theo de Raadt. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -%{ -#include <sys/types.h> -#include <sys/queue.h> - -#include <ctype.h> -#include <err.h> -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "got_error.h" -#include "gotweb.h" - -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - size_t ungetpos; - size_t ungetsize; - u_char *ungetbuf; - int eof_reached; - int lineno; -} *file, *topfile; -static const struct got_error* pushfile(struct file**, const char *); -int popfile(void); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...) - __attribute__((__format__ (printf, 1, 2))) - __attribute__((__nonnull__ (1))); -int kw_cmp(const void *, const void *); -int lookup(char *); -int igetc(void); -int lgetc(int); -void lungetc(int); -int findeol(void); - -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -struct sym { - TAILQ_ENTRY(sym) entry; - int used; - int persist; - char *nam; - char *val; -}; - -int symset(const char *, const char *, int); -int cmdline_symset(char *); -char *symget(const char *); - -const struct got_error* gerror = NULL; -struct gotweb_config *gw_conf; - -typedef struct { - union { - int64_t number; - char *string; - } v; - int lineno; -} YYSTYPE; - -%} - -%token GOT_WWW_PATH GOT_MAX_REPOS GOT_SITE_NAME GOT_SITE_OWNER GOT_SITE_LINK -%token GOT_LOGO GOT_LOGO_URL GOT_SHOW_REPO_OWNER GOT_SHOW_REPO_AGE -%token GOT_SHOW_REPO_DESCRIPTION GOT_MAX_REPOS_DISPLAY GOT_REPOS_PATH -%token GOT_MAX_COMMITS_DISPLAY ERROR GOT_SHOW_SITE_OWNER -%token GOT_SHOW_REPO_CLONEURL -%token <v.string> STRING -%token <v.number> NUMBER -%type <v.number> boolean -%% - -grammar : /* empty */ - | grammar '\n' - | grammar main '\n' - ; - -boolean : STRING { - if (strcasecmp($1, "true") == 0 || - strcasecmp($1, "on") == 0 || - strcasecmp($1, "yes") == 0) - $$ = 1; - else if (strcasecmp($1, "false") == 0 || - strcasecmp($1, "off") == 0 || - strcasecmp($1, "no") == 0) - $$ = 0; - else { - yyerror("invalid boolean value '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - ; -main : GOT_REPOS_PATH STRING { - gw_conf->got_repos_path = $2; - } - | GOT_WWW_PATH STRING { - gw_conf->got_www_path = $2; - } - | GOT_MAX_REPOS NUMBER { - if ($2 > 0) - gw_conf->got_max_repos = $2; - } - | GOT_SITE_NAME STRING { - gw_conf->got_site_name = $2; - } - | GOT_SITE_OWNER STRING { - gw_conf->got_site_owner = $2; - } - | GOT_SITE_LINK STRING { - gw_conf->got_site_link = $2; - } - | GOT_LOGO STRING { - gw_conf->got_logo = $2; - } - | GOT_LOGO_URL STRING { - gw_conf->got_logo_url = $2; - } - | GOT_SHOW_SITE_OWNER boolean { - gw_conf->got_show_site_owner = $2; - } - | GOT_SHOW_REPO_OWNER boolean { - gw_conf->got_show_repo_owner = $2; - } - | GOT_SHOW_REPO_AGE boolean { - gw_conf->got_show_repo_age = $2; - } - | GOT_SHOW_REPO_DESCRIPTION boolean { - gw_conf->got_show_repo_description = $2; - } - | GOT_SHOW_REPO_CLONEURL boolean { - gw_conf->got_show_repo_cloneurl = $2; - } - | GOT_MAX_REPOS_DISPLAY NUMBER { - if ($2 > 0) - gw_conf->got_max_repos_display = $2; - } - | GOT_MAX_COMMITS_DISPLAY NUMBER { - if ($2 > 0) - gw_conf->got_max_commits_display = $2; - } - ; -%% - -struct keywords { - const char *k_name; - int k_val; -}; - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - char *msg; - char *err = NULL; - - va_start(ap, fmt); - if (vasprintf(&msg, fmt, ap) == -1) { - gerror = got_error_from_errno("vasprintf"); - return 0; - } - va_end(ap); - if (asprintf(&err, "%s:%d: %s", file->name, yylval.lineno, msg) == -1) { - gerror = got_error_from_errno("asprintf"); - return(0); - } - gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err); - free(msg); - return(0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* This has to be sorted always. */ - static const struct keywords keywords[] = { - { "got_logo", GOT_LOGO }, - { "got_logo_url", GOT_LOGO_URL }, - { "got_max_commits_display", GOT_MAX_COMMITS_DISPLAY }, - { "got_max_repos", GOT_MAX_REPOS }, - { "got_max_repos_display", GOT_MAX_REPOS_DISPLAY }, - { "got_repos_path", GOT_REPOS_PATH }, - { "got_show_repo_age", GOT_SHOW_REPO_AGE }, - { "got_show_repo_cloneurl", GOT_SHOW_REPO_CLONEURL }, - { "got_show_repo_description", GOT_SHOW_REPO_DESCRIPTION }, - { "got_show_repo_owner", GOT_SHOW_REPO_OWNER }, - { "got_show_site_owner", GOT_SHOW_SITE_OWNER }, - { "got_site_link", GOT_SITE_LINK }, - { "got_site_name", GOT_SITE_NAME }, - { "got_site_owner", GOT_SITE_OWNER }, - { "got_www_path", GOT_WWW_PATH }, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) - return (p->k_val); - else - return (STRING); -} - -#define START_EXPAND 1 -#define DONE_EXPAND 2 - -static int expanding; - -int -igetc(void) -{ - int c; - - while (1) { - if (file->ungetpos > 0) - c = file->ungetbuf[--file->ungetpos]; - else - c = getc(file->stream); - - if (c == START_EXPAND) - expanding = 1; - else if (c == DONE_EXPAND) - expanding = 0; - else - break; - } - return (c); -} - -int -lgetc(int quotec) -{ - int c, next; - - if (quotec) { - if ((c = igetc()) == EOF) { - yyerror("reached end of file while parsing " - "quoted string"); - if (file == topfile || popfile() == EOF) - return (EOF); - return (quotec); - } - return (c); - } - - while ((c = igetc()) == '\\') { - next = igetc(); - if (next != '\n') { - c = next; - break; - } - yylval.lineno = file->lineno; - file->lineno++; - } - - if (c == EOF) { - /* - * Fake EOL when hit EOF for the first time. This gets line - * count right if last line in included file is syntactically - * invalid and has no newline. - */ - if (file->eof_reached == 0) { - file->eof_reached = 1; - return ('\n'); - } - while (c == EOF) { - if (file == topfile || popfile() == EOF) - return (EOF); - c = igetc(); - } - } - return (c); -} - -void -lungetc(int c) -{ - if (c == EOF) - return; - - if (file->ungetpos >= file->ungetsize) { - void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); - if (p == NULL) - err(1, "%s", __func__); - file->ungetbuf = p; - file->ungetsize *= 2; - } - file->ungetbuf[file->ungetpos++] = c; -} - -int -findeol(void) -{ - int c; - - /* Skip to either EOF or the first real EOL. */ - while (1) { - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; - -top: - p = buf; - while ((c = lgetc(0)) == ' ' || c == '\t') - ; /* nothing */ - - yylval.lineno = file->lineno; - if (c == '#') - while ((c = lgetc(0)) != '\n' && c != EOF) - ; /* nothing */ - if (c == '$' && !expanding) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - p = val + strlen(val) - 1; - lungetc(DONE_EXPAND); - while (p >= val) { - lungetc((unsigned char)*p); - p--; - } - lungetc(START_EXPAND); - goto top; - } - - switch (c) { - case '\'': - case '"': - quotec = c; - while (1) { - if ((c = lgetc(quotec)) == EOF) - return (0); - if (c == '\n') { - file->lineno++; - continue; - } else if (c == '\\') { - if ((next = lgetc(quotec)) == EOF) - return (0); - if (next == quotec || c == ' ' || c == '\t') - c = next; - else if (next == '\n') { - file->lineno++; - continue; - } else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; - break; - } else if (c == '\0') { - yyerror("syntax error"); - return (findeol()); - } - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - *p++ = c; - } - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - err(1, "%s", __func__); - return (STRING); - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((size_t)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && isdigit(c)); - lungetc(c); - if (p == buf + 1 && buf[0] == '-') - goto nodigits; - if (c == EOF || allowed_to_end_number(c)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - return (findeol()); - } - return (NUMBER); - } else { -nodigits: - while (p > buf + 1) - lungetc((unsigned char)*--p); - c = (unsigned char)*--p; - if (c == '-') - return (c); - } - } - -#define allowed_in_string(x) \ - (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && \ - x != '!' && x != '=' && x != '#' && \ - x != ',')) - - if (isalnum(c) || c == ':' || c == '_') { - do { - *p++ = c; - if ((size_t)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); - lungetc(c); - *p = '\0'; - if ((token = lookup(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - err(1, "%s", __func__); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -static const struct got_error* -pushfile(struct file **nfile, const char *name) -{ - const struct got_error* error = NULL; - - if (((*nfile) = calloc(1, sizeof(struct file))) == NULL) - return got_error_from_errno2(__func__, "calloc"); - if (((*nfile)->name = strdup(name)) == NULL) { - free(*nfile); - return got_error_from_errno2(__func__, "strdup"); - } - if (((*nfile)->stream = fopen((*nfile)->name, "re")) == NULL) { - char *msg = NULL; - if (asprintf(&msg, "%s", (*nfile)->name) == -1) - return got_error_from_errno("asprintf"); - error = got_error_msg(GOT_ERR_NO_CONFIG_FILE, msg); - free((*nfile)->name); - free((*nfile)); - free(msg); - return error; - } - (*nfile)->lineno = TAILQ_EMPTY(&files) ? 1 : 0; - (*nfile)->ungetsize = 16; - (*nfile)->ungetbuf = malloc((*nfile)->ungetsize); - if ((*nfile)->ungetbuf == NULL) { - fclose((*nfile)->stream); - free((*nfile)->name); - free((*nfile)); - return got_error_from_errno2(__func__, "malloc"); - } - TAILQ_INSERT_TAIL(&files, (*nfile), entry); - return error; -} - -int -popfile(void) -{ - struct file *prev = NULL; - - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file->ungetbuf); - free(file); - file = prev; - return (file ? 0 : EOF); -} - -const struct got_error* -parse_gotweb_config(struct gotweb_config **gconf, const char *filename) -{ - gw_conf = malloc(sizeof(struct gotweb_config)); - if (gw_conf == NULL) { - gerror = got_error_from_errno("malloc"); - goto done; - } - gw_conf->got_repos_path = strdup(D_GOTPATH); - if (gw_conf->got_repos_path == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_www_path = strdup(D_GOTWWW); - if (gw_conf->got_www_path == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_site_name = strdup(D_SITENAME); - if (gw_conf->got_site_name == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_site_owner = strdup(D_SITEOWNER); - if (gw_conf->got_site_owner == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_site_link = strdup(D_SITELINK); - if (gw_conf->got_site_link == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_logo = strdup(D_GOTLOGO); - if (gw_conf->got_logo == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_logo_url = strdup(D_GOTURL); - if (gw_conf->got_logo_url == NULL) { - gerror = got_error_from_errno("strdup"); - goto done; - } - gw_conf->got_show_site_owner = D_SHOWSOWNER; - gw_conf->got_show_repo_owner = D_SHOWROWNER; - gw_conf->got_show_repo_age = D_SHOWAGE; - gw_conf->got_show_repo_description = D_SHOWDESC; - gw_conf->got_show_repo_cloneurl = D_SHOWURL; - gw_conf->got_max_repos = D_MAXREPO; - gw_conf->got_max_repos_display = D_MAXREPODISP; - gw_conf->got_max_commits_display = D_MAXCOMMITDISP; - - /* - * We don't require that the gotweb config file exists - * So reset gerror if it doesn't exist and goto done. - */ - gerror = pushfile(&file, filename); - if (gerror && gerror->code == GOT_ERR_NO_CONFIG_FILE) { - gerror = NULL; - goto done; - } else if (gerror) - return gerror; - topfile = file; - - yyparse(); - popfile(); -done: - *gconf = gw_conf; - return gerror; -} - -int -symset(const char *nam, const char *val, int persist) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) { - if (strcmp(nam, sym->nam) == 0) - break; - } - - if (sym != NULL) { - if (sym->persist == 1) - return (0); - else { - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - } - if ((sym = calloc(1, sizeof(*sym))) == NULL) - return (-1); - - sym->nam = strdup(nam); - if (sym->nam == NULL) { - free(sym); - return (-1); - } - sym->val = strdup(val); - if (sym->val == NULL) { - free(sym->nam); - free(sym); - return (-1); - } - sym->used = 0; - sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entry); - return (0); -} - -int -cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - size_t len; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - - len = strlen(s) - strlen(val) + 1; - if ((sym = malloc(len)) == NULL) - errx(1, "cmdline_symset: malloc"); - - strlcpy(sym, s, len); - - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - -char * -symget(const char *nam) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) { - if (strcmp(nam, sym->nam) == 0) { - sym->used = 1; - return (sym->val); - } - } - return (NULL); -}
gotweb sunset