X-Git-Url: http://git.pjr.cc/?p=gwvp-mini.git;a=blobdiff_plain;f=gwvpmini%2Fgwvpmini_gitbackend.php;h=fb577f5336022c01e78d6775b05d397a916125c3;hp=a18421337f181c51cb4316246394d144f4883157;hb=cedd983dbbfcea17f6b3f5448009bd3175b37aa5;hpb=d2794eddc33e68af001c76caf06a38e70b75383e diff --git a/gwvpmini/gwvpmini_gitbackend.php b/gwvpmini/gwvpmini_gitbackend.php index a184213..fb577f5 100644 --- a/gwvpmini/gwvpmini_gitbackend.php +++ b/gwvpmini/gwvpmini_gitbackend.php @@ -26,16 +26,15 @@ function gwvpmini_gitControlCallMe() } -function gwvpmini_CreateRepoHooks($repopath, $cmdpath) +function gwvpmini_CreateRepoHooks($repopath, $cmdpath, $reponame) { $fp = fopen("$repopath/hooks/pre-receive", "w"); if(!$fp) error_log("could not create pre-receive hook"); // TODO: think about this one - $script = '#!/bin/bash'."\n\n".'DCOMMIT=`cat`'."\n".'START=`echo $DCOMMIT|cut -d " " -f 1`'."\n".'END=`echo $DCOMMIT|cut -d " " -f 2`'."\n".'REF=`echo $DCOMMIT|cut -d " " -f 3`'."\n\n"; - $script .= "php $cmdpath pre-receive "; - $script .= '$START $END $REF'."\n\n"; + //$script = '#!/bin/bash'."\n\n".'DCOMMIT=`cat`'."\n".'START=`echo $DCOMMIT|cut -d " " -f 1`'."\n".'END=`echo $DCOMMIT|cut -d " " -f 2`'."\n".'REF=`echo $DCOMMIT|cut -d " " -f 3`'."\n\n"; + $script = "#!/bin/bash\n\nDCOMMIT=".'`cat`'."\n\nphp $cmdpath $reponame \$REMOTE_USER pre-receive \$DCOMMIT\n\n"; fwrite($fp, $script); fclose($fp); @@ -48,9 +47,8 @@ function gwvpmini_CreateRepoHooks($repopath, $cmdpath) if(!$fp) error_log("could not create update hook"); // TODO: think about this one - $script = "#!/bin/bash\n\n"; - $script .= "php $cmdpath update "; - $script .= '$1 $2 $3'."\n\n"; + unset($script); + $script = "#!/bin/bash\n\nphp $cmdpath $reponame \$REMOTE_USER update \$1 \$2 \$3\n\n"; fwrite($fp, $script); fclose($fp); @@ -68,7 +66,8 @@ function gwvpmini_gitBackendInterface() header_remove("Set-Cookie"); header_remove("Expires"); header_remove("X-Powered-By"); - header_remove("Vary"); + header_remove("Vary"); + //header("Content-Encoding: none"); $repo_base = gwvpmini_getConfigVal("repodir"); @@ -77,16 +76,16 @@ function gwvpmini_gitBackendInterface() /* bizare git problem that ignores 403's or continues on with a push despite them - error_log("FLAP for ".$_SERVER["REQUEST_URI"]); + // error_log("FLAP for ".$_SERVER["REQUEST_URI"]); if(isset($_REQUEST)) { $dump = print_r($_REQUEST, true); - error_log("FLAP, $dump"); + // error_log("FLAP, $dump"); } if(isset($_SERVER["PHP_AUTH_USER"])) { - error_log("FLAP: donut hole"); + // error_log("FLAP: donut hole"); }*/ - + error_log("REQUESTINBACKEND: ".print_r($_REQUEST, true)); $repo = ""; $repoid = false; @@ -109,11 +108,12 @@ function gwvpmini_gitBackendInterface() // we do an update server cause its weird and i cant figure out when it actually needs to happen chdir("$repo_base/$repo.git"); - exec("/usr/bin/git update-server-info"); + // dont believe i have to do this + //exec("/usr/bin/git update-server-info"); if(!file_exists("$repo_base/$repo.git/hooks/pre-receive") || !file_exists("$repo_base/$repo.git/hooks/update")) { - error_log("WRITING HOOKS"); - gwvpmini_CreateRepoHooks("$repo_base/$repo.git", $cmd_line_tool); + // error_log("WRITING HOOKS"); + gwvpmini_CreateRepoHooks("$repo_base/$repo.git", $cmd_line_tool, $repo); } @@ -124,11 +124,11 @@ function gwvpmini_gitBackendInterface() $write = false; if(isset($_REQUEST["service"])) { if($_REQUEST["service"] == "git-receive-pack") { - error_log("got write as receivepack in post"); + // error_log("got write as receivepack in post"); $write = true; } } - + if(preg_match("/.*git-receive-pack$/", $_REQUEST["q"])) $write = true; //$write = true; // THIS MAY CAUSE ISSUES LATER ON but we do it cause the git client ignores our 403 when it uses git-receive-pack after an auth // no, this isnt a solution cause auth'd read attempts will come up as writes... @@ -142,17 +142,17 @@ function gwvpmini_gitBackendInterface() // next, figure out permissions for repo $rid = gwvpmini_GetRepoId($repo); $uid = -1; - error_log("AT THIS POINT WE HAVE $uid, $rid, $repo $person"); + // error_log("AT THIS POINT WE HAVE $uid, $rid, $repo $person"); if(!$person) { if($write) { - error_log("ASK FOR BASIC AUTH"); + // error_log("ASK FOR BASIC AUTH"); gwvpmini_AskForBasicAuth(); return; } else { $perm = gwvpmini_GetRepoPerm($rid, "a"); if($perm < 1) { - error_log("ASK FOR BASIC AUTH 2"); + // error_log("ASK FOR BASIC AUTH 2"); gwvpmini_AskForBasicAuth(); return; } @@ -162,7 +162,7 @@ function gwvpmini_gitBackendInterface() $perm = gwvpmini_GetRepoPerm($rid, $uid); if($write) { if($perm < 2) { - error_log("SEND FOFF"); + // error_log("SEND FOFF"); gwvpmini_fourZeroThree(); return; } @@ -182,8 +182,11 @@ function gwvpmini_gitBackendInterface() } // if its a write, we check (before and after) the branch/tag info to see if they were updated - //if($write) { - //} + if($write) { + error_log("REQUESTINBACKEND: processed as write"); + } else { + error_log("REQUESTINBACKEND: processed as read"); + } gwvpmini_callGitBackend($person, $repo); @@ -194,15 +197,15 @@ function gwvpmini_gitBackendInterface() // if we made it this far, we a read and we have permissions to do so, just search the file from the repo /*if(file_exists("$repo_base/$repo.git/$newloc")) { - error_log("would ask $repo for $repo.git/$newloc from $repo_base/$repo.git/$newloc"); + // error_log("would ask $repo for $repo.git/$newloc from $repo_base/$repo.git/$newloc"); $fh = fopen("$repo_base/$repo.git/$newloc", "rb"); - error_log("pushing file"); + // error_log("pushing file"); while(!feof($fh)) { echo fread($fh, 8192); } } else { - error_log("would ask $repo for $repo/$newloc from $repo_base/$repo/$newloc, NE"); + // error_log("would ask $repo for $repo/$newloc from $repo_base/$repo/$newloc, NE"); gwvpmini_fourZeroFour(); return; }*/ @@ -212,13 +215,15 @@ function gwvpmini_gitBackendInterface() function gwvpmini_canManageRepo($userid, $repoid) { // only the owner or an admin can do these tasks - error_log("Checking repoid, $repoid against userid $userid"); + // error_log("Checking repoid, $repoid against userid $userid"); if(gwvpmini_IsUserAdmin(null, null, $userid)) return true; if(gwvpmini_IsRepoOwner($userid, $repoid)) return true; return false; } + +// TODO: this whole bit needs a re-write function gwvpmini_callGitBackend($username, $repo) { // this is where things become a nightmare @@ -239,7 +244,7 @@ function gwvpmini_callGitBackend($username, $repo) $qs = ""; foreach($_REQUEST as $key => $var) { if($key != "q") { - //error_log("adding, $var from $key"); + //// error_log("adding, $var from $key"); if($qs == "") $qs.="$key=$var"; else $qs.="&$key=$var"; } @@ -269,7 +274,7 @@ function gwvpmini_callGitBackend($username, $repo) $procenv["REMOTE_ADDR"] = $_SERVER["REMOTE_ADDR"]; $procenv["AUTH_TYPE"] = "Basic"; - //error_log("PROCENV: ".print_r($procenv,true)); + //// error_log("PROCENV: ".print_r($procenv,true)); if(isset($_SERVER["CONTENT_TYPE"])) { $procenv["CONTENT_TYPE"] = $_SERVER["CONTENT_TYPE"]; @@ -279,12 +284,11 @@ function gwvpmini_callGitBackend($username, $repo) if(isset($_SERVER["CONTENT_LENGTH"])) { $procenv["CONTENT_LENGTH"] = $_SERVER["CONTENT_LENGTH"]; } + + $headers = getallheaders(); - error_log("path trans'd is /$repo_base/$repo.git/$euri from $ruri with ".$_REQUEST["q"]." $strrem"); - - + error_log("path trans'd is /$repo_base/$repo.git/$euri from $ruri with ".$_REQUEST["q"]." $strrem pre is ".print_r($_REQUEST,true)." and foff ".print_r($headers, true)); - $pwd = "/$repo_base/"; $proc = proc_open("/usr/lib/git-core/git-http-backend", array(array("pipe","rb"),array("pipe","wb"),array("file","/tmp/err", "a")), $pipes, $pwd, $procenv); @@ -293,13 +297,13 @@ function gwvpmini_callGitBackend($username, $repo) while(!$untilblank&&!feof($pipes[1])) { $lines_t = fgets($pipes[1]); $lines = trim($lines_t); - error_log("got line: $lines"); + // error_log("got line: $lines"); if($lines_t == "\r\n") { $untilblank = true; - error_log("now blank"); + // error_log("now blank"); } else header($lines); if($lines === false) { - error_log("got an unexpexted exit..."); + // error_log("got an unexpexted exit..."); exit(0); } @@ -310,21 +314,41 @@ function gwvpmini_callGitBackend($username, $repo) $continue = true; if(!stream_set_blocking($fh,0)) { - error_log("cant set input non-blocking"); + // error_log("cant set input non-blocking"); } if(!stream_set_blocking($pipes[1],0)) { - error_log("cant set pipe1 non-blocking"); + // error_log("cant set pipe1 non-blocking"); } $stlimit = 0; $fp = fopen("/tmp/gitup.".rand(0,4000000), "w"); + $from_client_data = ""; // i was going to use stream_select, but i feel this works better like this while($continue) { // do client + + // lets start again.... + if(!feof($fh)) { - $from_client_data = fread($fh,8192); + if(isset($headers["Content-Length"])) { + $cl = $headers["Content-Length"]; + while(strlen($from_client_data) < $cl) { + error_log("re-read ".strlen($from_client_data)); + $from_client_data .= fread($fh, $cl); + } + } else $from_client_data = fread($fh,8192); + + // TODO: BIG TODO: must rewrite this bit. its ugly as sin, it works, but it probably shouldnt. + + if(isset($headers["Content-Encoding"])) { + if($headers["Content-Encoding"] == "gzip") { + //error_log("DAM YOU GIT CLIENT and your retarded gzip encoding"); + $from_client_data = gzinflate(substr($from_client_data, 10)); + //$from_client_data = gzdecode($from_client_data); + } + } if($from_client_data !== false) { fwrite($pipes[0], $from_client_data); fwrite($fp, $from_client_data); @@ -338,6 +362,9 @@ function gwvpmini_callGitBackend($username, $repo) //$continue = false; } + + + // do cgi // sometimes, we get a \r\n from the cgi, i do not know why she swallowed the fly, // but i do know that the fgets for the headers above should have comsued that @@ -364,27 +391,30 @@ function gwvpmini_callGitBackend($username, $repo) } if($from_cgi_data !== false) { + error_log("send to client"); echo $from_cgi_data; flush(); } $cgi_len = strlen($from_cgi_data); } else { - error_log("cgi end"); + // error_log("cgi end"); $cgi_len = 0; } + flush(); + if(feof($pipes[1])) $continue = false; else { if($client_len == 0 && $cgi_len == 0) { usleep(200000); error_log("sleep tick"); $stlimit++; - if($stlimit > 2) $continue = false; + if($stlimit > 5000) $continue = false; } else { $stlimit = 0; error_log("sizes: $client_len, $cgi_len"); if($cgi_len > 0) { - error_log("from cgi: \"$from_cgi_data\""); + //error_log("from cgi: \"$from_cgi_data\""); } } } @@ -392,10 +422,15 @@ function gwvpmini_callGitBackend($username, $repo) } + flush(); + error_log("and im done..."); + //fclose($fl); fclose($fh); fclose($pipes[1]); fclose($pipes[0]); + + exit(0); } @@ -412,21 +447,153 @@ function gwvpmini_repoExists($name) // 0 - anyone can clone/read, only owner can write // 1 - noone can clone/read, repo is visible (i.e. name), only owner can read/write repo // 2 - only owner can see anything -function gwvpmini_createGitRepo($name, $ownerid, $desc) +function gwvpmini_createGitRepo($name, $ownerid, $desc, $defperms, $clonefrom, $isremoteclone) { + global $cmd_line_tool; + $repo_base = gwvpmini_getConfigVal("repodir"); + if($clonefrom !== false) { + error_log("how did i end up in clonefrom? $clonefrom"); + if(!$isremoteclone) { + exec("/usr/bin/git clone --bare $repo_base/$clonefrom.git $repo_base/$name.git >> /tmp/gitlog 2>&1"); + gwvpmini_AddRepo($name, $desc, $ownerid, $defperms, $clonefrom); + } else { + // we do this from an outside call in the background + $cmd = "/usr/bin/php $cmd_line_tool $clonefrom $name backgroundclone >> /tmp/gitlog 2>&1 &"; + error_log("cmd called as $cmd"); + exec($cmd); + gwvpmini_AddRepo($name, $desc, $ownerid, $defperms, $clonefrom); + $rn = gwvpmini_getRepo(null, $name, null); + $rid = $rn["id"]; + gwvpmini_SetRepoCloning($rid); + gwvpmini_SendMessageByDb("info", "Background clone initiated for $name ($rid) from $clonefrom... your repo will be available once the background clone is finished", $ownerid); + return false; + } + } else { + // phew, this works, but i tell you this - bundles arent quite as nice as they should be - error_log("would create $repo_base/$name.git"); - exec("/usr/bin/git init $repo_base/$name.git --bare > /tmp/gitlog 2>&1"); - chdir("$repo_base/$name.git"); - exec("/usr/bin/git update-server-info"); - - // gwvpmini_AddRepo($reponame, $repodesc, $repoowner, $defaultperms = 0) - gwvpmini_AddRepo($name, $desc, $ownerid); + // error_log("would create $repo_base/$name.git"); + exec("/usr/bin/git init $repo_base/$name.git --bare >> /tmp/gitlog 2>&1"); + chdir("$repo_base/$name.git"); + exec("/usr/bin/git update-server-info"); + + // gwvpmini_AddRepo($reponame, $repodesc, $repoowner, $defaultperms = 0) + gwvpmini_AddRepo($name, $desc, $ownerid, $defperms, $clonefrom); + } return true; } - +function gzdecode($data,&$filename='',&$error='',$maxlength=null) +{ + $len = strlen($data); + if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) { + $error = "Not in GZIP format."; + return null; // Not GZIP format (See RFC 1952) + } + $method = ord(substr($data,2,1)); // Compression method + $flags = ord(substr($data,3,1)); // Flags + if ($flags & 31 != $flags) { + $error = "Reserved bits not allowed."; + return null; + } + // NOTE: $mtime may be negative (PHP integer limitations) + $mtime = unpack("V", substr($data,4,4)); + $mtime = $mtime[1]; + $xfl = substr($data,8,1); + $os = substr($data,8,1); + $headerlen = 10; + $extralen = 0; + $extra = ""; + if ($flags & 4) { + // 2-byte length prefixed EXTRA data in header + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $extralen = unpack("v",substr($data,8,2)); + $extralen = $extralen[1]; + if ($len - $headerlen - 2 - $extralen < 8) { + return false; // invalid + } + $extra = substr($data,10,$extralen); + $headerlen += 2 + $extralen; + } + $filenamelen = 0; + $filename = ""; + if ($flags & 8) { + // C-style string + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $filenamelen = strpos(substr($data,$headerlen),chr(0)); + if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) { + return false; // invalid + } + $filename = substr($data,$headerlen,$filenamelen); + $headerlen += $filenamelen + 1; + } + $commentlen = 0; + $comment = ""; + if ($flags & 16) { + // C-style string COMMENT data in header + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $commentlen = strpos(substr($data,$headerlen),chr(0)); + if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) { + return false; // Invalid header format + } + $comment = substr($data,$headerlen,$commentlen); + $headerlen += $commentlen + 1; + } + $headercrc = ""; + if ($flags & 2) { + // 2-bytes (lowest order) of CRC32 on header present + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff; + $headercrc = unpack("v", substr($data,$headerlen,2)); + $headercrc = $headercrc[1]; + if ($headercrc != $calccrc) { + $error = "Header checksum failed."; + return false; // Bad header CRC + } + $headerlen += 2; + } + // GZIP FOOTER + $datacrc = unpack("V",substr($data,-8,4)); + $datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF); + $isize = unpack("V",substr($data,-4)); + $isize = $isize[1]; + // decompression: + $bodylen = $len-$headerlen-8; + if ($bodylen < 1) { + // IMPLEMENTATION BUG! + return null; + } + $body = substr($data,$headerlen,$bodylen); + $data = ""; + if ($bodylen > 0) { + switch ($method) { + case 8: + // Currently the only supported compression method: + $data = gzinflate($body,$maxlength); + break; + default: + $error = "Unknown compression method."; + return false; + } + } // zero-byte body content is allowed + // Verifiy CRC32 + $crc = sprintf("%u",crc32($data)); + $crcOK = $crc == $datacrc; + $lenOK = $isize == strlen($data); + if (!$lenOK || !$crcOK) { + $error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.'); + return false; + } + return $data; +} ?> \ No newline at end of file