From: Nishi Date: Wed, 21 Aug 2024 04:31:55 +0000 (+0000) Subject: can show file now X-Git-Url: https://git.chaotic.ninja/gitweb/nishi/?a=commitdiff_plain;h=1095e1c45afaa0a8160f00bc24c4db1eeec88643;p=repoview.git can show file now git-svn-id: file:///raid/svn-personal/repoview/trunk@11 7e8b2a19-8934-dd40-8cb3-db22cdd5a80f --- diff --git a/CGI/repo.c b/CGI/repo.c index 96e70fd..d802430 100644 --- a/CGI/repo.c +++ b/CGI/repo.c @@ -1,3 +1,269 @@ /* $Id$ */ #include "rv_repo.h" + +#include "../config.h" + +#include "rv_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char* rv_construct_repouser(const char* reponame, const char* username) { + char cbuf[2]; + cbuf[0] = REPO_USER_DELIM; + cbuf[1] = 0; + return rv_strcat3(reponame, cbuf, username); +} + +bool rv_repo_exists(const char* repouser) { + char* path = rv_strcat3(SVN_ROOT, "/", repouser); + if(access(path, F_OK) == 0) { + free(path); + return true; + } + return false; +} + +void rv_repo_list(const char* username, void (*handler)(const char* name, const char* rev)) { + struct dirent** nl; + int n = scandir(SVN_ROOT, &nl, NULL, alphasort); + if(n < 0) return; + int i; + for(i = 0; i < n; i++) { + if(strcmp(nl[i]->d_name, "..") != 0 && strcmp(nl[i]->d_name, ".") != 0) { + char* tmp = rv_strcat3(SVN_ROOT, "/", nl[i]->d_name); + char* path = rv_strcat(tmp, "/db/current"); + free(tmp); + char* str = rv_strdup(nl[i]->d_name); + int j; + for(j = 0; str[j] != 0; j++) { + if(str[j] == REPO_USER_DELIM) { + str[j] = 0; + if(strcmp(str + j + 1, username) == 0) { + struct stat s; + char* rev = rv_strdup("???"); + if(stat(path, &s) == 0) { + free(rev); + rev = malloc(s.st_size + 1); + FILE* f = fopen(path, "r"); + fread(rev, 1, s.st_size, f); + fclose(f); + rev[s.st_size] = 0; + } + handler(str, rev); + free(rev); + } + break; + } + } + free(path); + free(str); + } + free(nl[i]); + } + free(nl); +} + +void null_exec(char** cmd) { + pid_t pid = fork(); + if(pid == 0) { + int null = open("/dev/null", O_RDWR); + dup2(STDOUT_FILENO, null); + execvp(cmd[0], cmd); + _exit(0); + } else { + waitpid(pid, 0, 0); + } +} + +void rv_create_repo(const char* repouser) { + char* user = rv_strdup(repouser); + int i; + for(i = 0; user[i] != 0; i++) { + if(user[i] == REPO_USER_DELIM) { + user[i] = 0; + break; + } + } + char* path = rv_strcat3(SVN_ROOT, "/", repouser); + char* cmd[] = {"svnadmin", "create", path, NULL}; + null_exec(cmd); + free(path); + FILE* f = fopen(APACHE_AUTHZ, "r+"); + lockf(fileno(f), F_LOCK, 0); + + fseek(f, 0, SEEK_END); + + fprintf(f, "#%%START %s\n", repouser); + fprintf(f, "* = r\n"); + fprintf(f, "%s = r\n", user); + fprintf(f, "#%%END\n"); + + lockf(fileno(f), F_ULOCK, 0); + free(user); +} + +char* rv_get_readme(const char* repouser) { + char* tmp = rv_strcat3(SVN_ROOT, "/", repouser); + char* path = rv_strcat(tmp, "/README.txt"); + free(tmp); + struct stat s; + if(stat(path, &s) == 0) { + FILE* f = fopen(path, "r"); + char* buf = malloc(s.st_size + 1); + fread(buf, 1, s.st_size, f); + fclose(f); + buf[s.st_size] = 0; + return buf; + } + return NULL; +} + +long long rv_get_filesize(const char* repouser, const char* path) { + char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser); + int pipes[2]; + pipe(pipes); + pid_t pid = fork(); + if(pid == 0) { + close(pipes[0]); + dup2(pipes[1], STDOUT_FILENO); + char* cmd[] = {"svnlook", "filesize", svnpath, (char*)path, NULL}; + execvp("svnlook", cmd); + _exit(0); + } else { + close(pipes[1]); + char cbuf[2]; + cbuf[1] = 0; + char* d = malloc(1); + d[0] = 0; + while(1) { + int n = read(pipes[0], cbuf, 1); + if(n == 0) break; + char* tmp = d; + d = rv_strcat(tmp, cbuf); + free(tmp); + } + int status; + waitpid(pid, &status, 0); + if(WEXITSTATUS(status) != 0) { + free(d); + free(svnpath); + return -1; + } + long long sz = atoll(d); + free(svnpath); + free(d); + return sz; + } +} + +bool rv_get_list(const char* repouser, const char* path, void (*handler)(const char* pathname), int* isdir) { + char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser); + int pipes[2]; + *isdir = 0; + pipe(pipes); + pid_t pid = fork(); + if(pid == 0) { + close(pipes[0]); + dup2(pipes[1], STDOUT_FILENO); + char* cmd[] = {"svnlook", "-N", "tree", svnpath, (char*)path, NULL}; + execvp("svnlook", cmd); + _exit(0); + } else { + close(pipes[1]); + char cbuf[2]; + cbuf[1] = 0; + char* d = malloc(1); + d[0] = 0; + while(1) { + int n = read(pipes[0], cbuf, 1); + if(n == 0) break; + char* tmp = d; + d = rv_strcat(tmp, cbuf); + free(tmp); + } + int status; + waitpid(pid, &status, 0); + if(WEXITSTATUS(status) != 0) { + free(d); + free(svnpath); + return false; + } + int count = 0; + int incr = 0; + int i; + int phase = 0; + repeat: + for(i = 0;; i++) { + if(d[i] == '\r') { + d[i] = 0; + } else if(d[i] == '\n' || d[i] == 0) { + char oldc = d[i]; + d[i] = 0; + count++; + if(count > 1 && strlen(d + incr + 1) > 0 && d[incr] != 0) { + char* pathname = d + incr + 1; + if(phase == 0 && pathname[strlen(pathname) - 1] == '/') { + handler(d + incr + 1); + } else if(phase == 1 && pathname[strlen(pathname) - 1] != '/') { + handler(d + incr + 1); + } + } else { + char* pathname = d + incr; + if(pathname[strlen(pathname) - 1] == '/') *isdir = 1; + } + d[i] = oldc; + incr = i + 1; + if(oldc == 0) break; + } + } + phase++; + if(phase == 1) goto repeat; + free(d); + } + free(svnpath); + return true; +} + +char* rv_read_file(const char* repouser, char* path) { + char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser); + int pipes[2]; + pipe(pipes); + pid_t pid = fork(); + if(pid == 0) { + close(pipes[0]); + dup2(pipes[1], STDOUT_FILENO); + char* cmd[] = {"svnlook", "cat", svnpath, (char*)path, NULL}; + execvp("svnlook", cmd); + _exit(0); + } else { + close(pipes[1]); + char cbuf[2]; + cbuf[1] = 0; + char* d = malloc(1); + d[0] = 0; + while(1) { + int n = read(pipes[0], cbuf, 1); + if(n == 0) break; + char* tmp = d; + d = rv_strcat(tmp, cbuf); + free(tmp); + } + int status; + waitpid(pid, &status, 0); + if(WEXITSTATUS(status) != 0) { + free(d); + free(svnpath); + return NULL; + } + return d; + } +} diff --git a/CGI/rv_repo.h b/CGI/rv_repo.h index e548190..e62bf3c 100644 --- a/CGI/rv_repo.h +++ b/CGI/rv_repo.h @@ -3,4 +3,15 @@ #ifndef __RV_REPO_H__ #define __RV_REPO_H__ +#include + +char* rv_construct_repouser(const char* reponame, const char* username); +bool rv_repo_exists(const char* repouser); +void rv_repo_list(const char* username, void (*handler)(const char* name, const char* rev)); +void rv_create_repo(const char* repouser); +char* rv_get_readme(const char* repouser); +bool rv_get_list(const char* repouser, const char* path, void (*handler)(const char* pathname), int* isdir); +char* rv_read_file(const char* repouser, char* path); +long long rv_get_filesize(const char* repouser, const char* path); + #endif diff --git a/CGI/theme/modern.c b/CGI/theme/modern.c index 3272419..b834646 100644 --- a/CGI/theme/modern.c +++ b/CGI/theme/modern.c @@ -6,6 +6,7 @@ #include "rv_version.h" #include "rv_auth.h" #include "rv_db.h" +#include "rv_repo.h" #include "../../config.h" @@ -21,8 +22,144 @@ char* title = NULL; char* desc = NULL; char* page = NULL; char* nav = NULL; +char* grepouser; extern char* user; +char* url_escape(const char* input) { + const char hex[] = "0123456789ABCDEF"; + char* r = malloc(1); + r[0] = 0; + char cbuf[2]; + cbuf[1] = 0; + int i; + for(i = 0; input[i] != 0; i++) { + if(input[i] == 0x20 || input[i] == 0x22 || input[i] == 0x25 || input[i] == 0x2d || input[i] == 0x2e || input[i] == 0x3c || input[i] == 0x3e || input[i] == 0x5c || input[i] == 0x5e || input[i] == 0x5f || input[i] == 0x60 || input[i] == 0x7b || input[i] == 0x7c || input[i] == 0x7d || input[i] == 0x7e || input[i] == 0x21 || input[i] == 0x23 || input[i] == 0x24 || input[i] == 0x26 || input[i] == 0x27 || input[i] == 0x28 || input[i] == 0x29 || input[i] == 0x2a || input[i] == 0x2b || input[i] == 0x2c || input[i] == 0x2f || input[i] == 0x3a || input[i] == 0x3b || input[i] == 0x3d || input[i] == 0x3f || input[i] == 0x40 || input[i] == 0x5b || input[i] == 0x5d) { + add_data(&r, "%"); + cbuf[0] = hex[(input[i] >> 4) & 0xf]; + add_data(&r, cbuf); + cbuf[0] = hex[input[i] & 0xf]; + add_data(&r, cbuf); + } else { + cbuf[0] = input[i]; + add_data(&r, cbuf); + } + } + return r; +} + +char* html_escape(const char* input) { + char* r = malloc(1); + r[0] = 0; + char cbuf[2]; + cbuf[1] = 0; + int i; + for(i = 0; input[i] != 0; i++) { + if(input[i] == '<') { + add_data(&r, "<"); + } else if(input[i] == '>') { + add_data(&r, ">"); + } else { + cbuf[0] = input[i]; + add_data(&r, cbuf); + } + } + return r; +} + +char* html_escape_nl_to_br(const char* input) { + char* r = malloc(1); + r[0] = 0; + char cbuf[2]; + cbuf[1] = 0; + int i; + for(i = 0; input[i] != 0; i++) { + if(input[i] == '<') { + add_data(&r, "<"); + } else if(input[i] == '>') { + add_data(&r, ">"); + } else if(input[i] == '\n') { + add_data(&r, "
"); + } else { + cbuf[0] = input[i]; + add_data(&r, cbuf); + } + } + return r; +} + +void list_repo(const char* name, const char* rev) { + char* showname = html_escape(name); + char* urluser = url_escape(user); + char* urlrepo = url_escape(name); + add_data(&page, ""); + add_data(&page, ""); + add_data(&page, showname); + add_data(&page, ""); + add_data(&page, ""); + add_data(&page, rev); + add_data(&page, ""); + add_data(&page, ""); + free(showname); + free(urluser); + free(urlrepo); +} + +int fcounter = 0; +void list_files(const char* pathname) { + if(fcounter == 0) { + add_data(&nav, "
  • File List
  • \n"); + add_data(&page, "

    File List

    \n"); + add_data(&page, "NameSize\n"); + } + fcounter++; + add_data(&page, ""); + add_data(&page, pathname); + add_data(&page, "\n"); + add_data(&page, "\n"); + if(strcmp(sz, "-1") != 0) { + add_data(&page, sz); + } else { + add_data(&page, "<DIR>"); + } + add_data(&page, "\n"); + free(sz); + add_data(&page, "\n"); + free(query); + free(urlpath); +} + void render_page(void) { rv_load_query('Q'); char* query = rv_get_query("page"); @@ -61,7 +198,11 @@ void render_page(void) { page = rv_strdup(""); rv_load_query('P'); - if(rv_get_query("username") == NULL || rv_get_query("password") == NULL) { + if(user != NULL) { + page = rv_strdup("It looks like you are already logged in.
    Want to log out?\n"); + } else if(rv_get_query("username") == NULL || rv_get_query("password") == NULL) { add_data(&page, "Invalid form.\n"); } else { if(rv_has_user(rv_get_query("username"))) { @@ -104,6 +245,9 @@ void render_page(void) { add_data(&page, INSTANCE_ROOT); add_data(&page, "/?page=login\">log in?\n"); } else { + char cbuf[2]; + cbuf[0] = REPO_USER_DELIM; + cbuf[1] = 0; nav = rv_strdup(""); add_data(&nav, "
  • Create a repository
  • \n"); add_data(&nav, "
  • Repository List
  • \n"); @@ -121,8 +265,65 @@ void render_page(void) { add_data(&page, " \n"); add_data(&page, " \n"); add_data(&page, " \n"); + add_data(&page, "Repository name cannot contain '"); + add_data(&page, cbuf); + add_data(&page, "'."); add_data(&page, "\n"); add_data(&page, "

    Repository List

    \n"); + add_data(&page, "\n"); + add_data(&page, "\n"); + rv_repo_list(user, list_repo); + add_data(&page, "
    Repository nameRevision
    \n"); + } + } else if(strcmp(query, "createrepo") == 0) { + title = rv_strdup("Creating Repository Result"); + page = rv_strdup(""); + + rv_load_query('P'); + if(user == NULL) { + page = rv_strdup("It looks like you are not logged in.
    Want to log in?\n"); + } else if(rv_get_query("name") == NULL) { + add_data(&page, "Invalid form.\n"); + } else { + int i; + bool reject = false; + char* name = rv_get_query("name"); + for(i = 0; name[i] != 0; i++) { + if(name[i] == REPO_USER_DELIM) { + char cbuf[2]; + cbuf[0] = REPO_USER_DELIM; + cbuf[1] = 0; + add_data(&page, "Repository name cannot contain '"); + add_data(&page, cbuf); + add_data(&page, "'."); + reject = true; + break; + } + } + if(!reject) { + char* ru = rv_construct_repouser(name, user); + if(rv_repo_exists(ru)) { + add_data(&page, "Repository already exists."); + } else { + char* esc; + rv_create_repo(ru); + add_data(&page, "Repository has been created.
    \n"); + add_data(&page, "Go to the repository.\n"); + } + free(ru); + } } } else if(strcmp(query, "logout") == 0) { title = rv_strdup("Logout"); @@ -140,6 +341,56 @@ void render_page(void) { add_data(&page, " \n"); add_data(&page, "\n"); } + } else if(strcmp(query, "repo") == 0) { + title = rv_strdup("Repository"); + desc = rv_strdup(""); + page = rv_strdup(""); + nav = rv_strdup(""); + if(rv_get_query("username") == NULL || rv_get_query("reponame") == NULL) { + add_data(&page, "Required parameters not set."); + } else { + char* user = rv_get_query("username"); + char* repo = rv_get_query("reponame"); + char* repouser = rv_construct_repouser(repo, user); + grepouser = repouser; + if(rv_repo_exists(repouser)) { + char* showuser = html_escape(user); + char* showrepo = html_escape(repo); + char* showreadme = rv_get_readme(repouser); + desc = html_escape_nl_to_br(showreadme); + add_data(&title, " - "); + add_data(&title, showrepo); + add_data(&title, "/"); + add_data(&title, showuser); + free(showuser); + free(showrepo); + free(showreadme); + + int isdir; + char* path = rv_get_query("path"); + if(path == NULL) path = "/"; + fcounter = 0; + add_data(&page, ""); + if(!rv_get_list(repouser, path, list_files, &isdir)) { + add_data(&page, "\n"); + } + add_data(&page, "
    Path not found.
    "); + if(isdir == 0) { + add_data(&nav, "
  • Content
  • "); + add_data(&page, "

    Content

    \n"); + add_data(&page, "
    ");
    +					char* data = rv_read_file(repouser, path);
    +					char* esc = html_escape_nl_to_br(data);
    +					add_data(&page, esc);
    +					free(esc);
    +					free(data);
    +					add_data(&page, "
    "); + } + } else { + add_data(&page, "Repository does not exist.\n"); + } + free(repouser); + } } if(title == NULL) title = rv_strdup(""); @@ -208,6 +459,9 @@ void render_stuff(void) { add_data(&buffer, " padding-right: 25px;\n"); add_data(&buffer, " padding-top: 7px;\n"); add_data(&buffer, "}\n"); + add_data(&buffer, "th,td {\n"); + add_data(&buffer, " padding: 2px;\n"); + add_data(&buffer, "}\n"); add_data(&buffer, "body {\n"); add_data(&buffer, " background-color: #1F4677;\n"); add_data(&buffer, " width: 940px;\n"); @@ -225,6 +479,10 @@ void render_stuff(void) { add_data(&buffer, " font-size: 22px;\n"); add_data(&buffer, " font-weight: bold;\n"); add_data(&buffer, "}\n"); + add_data(&buffer, "pre {\n"); + add_data(&buffer, " background-color: #dddddd;\n"); + add_data(&buffer, " border: solid 2px #bbbbbb;\n"); + add_data(&buffer, "}\n"); add_data(&buffer, "#index {\n"); add_data(&buffer, " list-style: none;\n"); add_data(&buffer, " line-height: normal;\n"); @@ -239,6 +497,9 @@ void render_stuff(void) { add_data(&buffer, "}\n"); add_data(&buffer, "#descinside {\n"); add_data(&buffer, " float: left;\n"); + add_data(&buffer, " width: 700px;\n"); + add_data(&buffer, " overflow-y: scroll;\n"); + add_data(&buffer, " max-height: 128px;\n"); add_data(&buffer, "}\n"); add_data(&buffer, "#logo {\n"); add_data(&buffer, " float: right;\n"); @@ -247,7 +508,6 @@ void render_stuff(void) { add_data(&buffer, " background-color: #FFFFFF;\n"); add_data(&buffer, " margin: -10px auto;\n"); add_data(&buffer, " padding: 8px 24px 24px;\n"); - add_data(&buffer, " min-height: 128px;\n"); add_data(&buffer, "}\n"); add_data(&buffer, "#pageindex {\n"); add_data(&buffer, " background-color: #FFFFFF;\n"); @@ -352,8 +612,8 @@ void render_stuff(void) { add_data(&buffer, " \n"); add_data(&buffer, "
    \n"); add_data(&buffer, page); - add_data(&buffer, "
    \n"); add_data(&buffer, "
    \n"); + add_data(&buffer, "
    \n"); add_data(&buffer, " \n"); add_data(&buffer, "
    \n"); add_data(&buffer, "
    \n"); diff --git a/CGI/util.c b/CGI/util.c index 4c84ecb..ef8d199 100644 --- a/CGI/util.c +++ b/CGI/util.c @@ -75,13 +75,6 @@ char* rv_url_decode(const char* str) { return r; } -char* rv_construct_repouser(const char* reponame, const char* username) { - char cbuf[2]; - cbuf[0] = REPO_USER_DELIM; - cbuf[1] = 0; - return rv_strcat3(reponame, cbuf, username); -} - char* rv_new_token(const char* username) { const char tokenstr[] = "0123456789abcdefghijklmnopqrstuvwxyz"; char* token = malloc(17); diff --git a/config.h.tmpl b/config.h.tmpl index 9c2d89c..f2d25c9 100644 --- a/config.h.tmpl +++ b/config.h.tmpl @@ -26,7 +26,7 @@ #define INSTANCE_REPEAT "resize-x" /* Repository/User delimeter. This character will be unusable in the username/repository name. */ -#define REPO_USER_DELIM '@' +#define REPO_USER_DELIM '$' /* Theme. */ #define USE_MODERN