/* ui-clone.c: functions for http cloning, based on * git's http-backend.c by Shawn O. Pearce * * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com> * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */#include"cgit.h"#include"ui-clone.h"#include"html.h"#include"ui-shared.h"#include"packfile.h"#include"object-store.h"staticintprint_ref_info(constchar*refname,conststructobject_id*oid,intflags,void*cb_data){structobject*obj;if(!(obj=parse_object(the_repository,oid)))return0;htmlf("%s\t%s\n",oid_to_hex(oid),refname);if(obj->type==OBJ_TAG){if(!(obj=deref_tag(the_repository,obj,refname,0)))return0;htmlf("%s\t%s^{}\n",oid_to_hex(&obj->oid),refname);}return0;}staticvoidprint_pack_info(void){structpacked_git*pack;char*offset;ctx.page.mimetype="text/plain";ctx.page.filename="objects/info/packs";cgit_print_http_headers();reprepare_packed_git(the_repository);for(pack=get_packed_git(the_repository);pack;pack=pack->next){if(pack->pack_local){offset=strrchr(pack->pack_name,'/');if(offset&&offset[1]!='\0')++offset;elseoffset=pack->pack_name;htmlf("P %s\n",offset);}}}staticvoidsend_file(constchar*path){structstatst;if(stat(path,&st)){switch(errno){caseENOENT:cgit_print_error_page(404,"Not found","Not found");break;caseEACCES:cgit_print_error_page(403,"Forbidden","Forbidden");break;default:cgit_print_error_page(400,"Bad request","Bad request");}return;}ctx.page.mimetype="application/octet-stream";ctx.page.filename=path;skip_prefix(path,ctx.repo->path,&ctx.page.filename);skip_prefix(ctx.page.filename,"/",&ctx.page.filename);cgit_print_http_headers();html_include(path);}voidcgit_clone_info(void){if(!ctx.qry.path||strcmp(ctx.qry.path,"refs")){cgit_print_error_page(400,"Bad request","Bad request");return;}ctx.page.mimetype="text/plain";ctx.page.filename="info/refs";cgit_print_http_headers();for_each_ref(print_ref_info,NULL);}voidcgit_clone_objects(void){char*p;if(!ctx.qry.path)gotoerr;if(!strcmp(ctx.qry.path,"info/packs")){print_pack_info();return;}/* Avoid directory traversal by forbidding "..", but also work around * other funny business by just specifying a fairly strict format. For * example, now we don't have to stress out about the Cygwin port. */for(p=ctx.qry.path;*p;++p){if(*p=='.'&&*(p+1)=='.')gotoerr;if(!isalnum(*p)&&*p!='/'&&*p!='.'&&*p!='-')gotoerr;}send_file(git_path("objects/%s",ctx.qry.path));return;err:cgit_print_error_page(400,"Bad request","Bad request");}voidcgit_clone_head(void){send_file(git_path("%s","HEAD"));}