<?php // // This is a set of fixes that must be applied when the software is upgraded. // If the structure of authorized_keys may change, we must add a fix to // regenerate the keys. // include_once($INC . "/sql.inc.php"); include_once($INC . "/state.inc.php"); include_once($INC . "/util.inc.php"); include_once($INC . "/user.inc.php"); include_once($INC . "/repo.inc.php"); include_once($INC . "/keys.inc.php"); $rg_fixes = array(); $rg_fixes[1] = array("rg_fixes_user_index_by_id"); $rg_fixes[2] = array("rg_fixes_repo_index_by_id"); $rg_fixes[3] = array("rg_fixes_keys_regen"); $rg_fixes[4] = array("rg_fixes_repos_last_bug_id"); $rg_fixes[5] = array("rg_fixes_wh_ver2"); // This must be the last line $rg_fixes_ver = count($rg_fixes); /* * Get rid of bugs_max database */ function rg_fixes_repos_last_bug_id($db) { rg_log_enter("rg_fixes_repos_last_bug_id"); $ret = FALSE; while (1) { $res = rg_sql_begin($db); if (!$res) break; $sql = "SELECT * FROM bugs_max"; $res = rg_sql_query($db, $sql); if (!$res) break; $error = FALSE; while (($row = rg_sql_fetch_array($res))) { $repo_id = $row['repo_id']; $last = $row['last_bug_id']; $params = array("repo_id" => $repo_id, "last" => $last); $sql = "UPDATE repos SET last_bug_id = @@last@@" . " WHERE repo_id = @@repo_id@@"; $res2 = rg_sql_query_params($db, $sql, $params); if (!$res2) { $error = TRUE; break; } rg_sql_free_result($res2); } rg_sql_free_result($res); if ($error) break; $sql = "DROP TABLE bugs_max"; $res = rg_sql_query($db, $sql); if (!$res) break; $res = rg_sql_commit($db); if (!$res) break; $ret = TRUE; break; } rg_log_exit(); return $ret; } /* * Just regenerate the keys */ function rg_fixes_keys_regen($db) { rg_log_enter("fixes_keys_regen"); $ret = rg_keys_regen($db); if ($ret === FALSE) rg_log("Could not regenerate keys: " . rg_keys_error() . "!"); rg_log_exit(); return $ret; } /* * Fix one repo (make the names as relative links to ids) */ function rg_fixes_repo_index_by_id_one($uid, $repo_id, $repo_name) { global $php_errormsg; rg_log_enter("fixes_repo_index_by_id_one:" . " uid=$uid repo_id=$repo_id repo_name=$repo_name"); $ret = FALSE; while (1) { // we expect to have a folder .../repos/by_id $by_id = rg_repo_path_by_id($uid, $repo_id); $p = dirname($by_id); if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) { rg_log("Cannot create [$p] folder!"); break; } // we expect to have a folder .../repos/by_name $by_name = rg_repo_path_by_name($uid, $repo_name); $p = dirname($by_name); if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) { rg_log("Cannot create [$p] folder!"); break; } // We already moved it? $new_path = rg_repo_path_by_id($uid, $repo_id); if (!is_dir($new_path)) { $old_path = rg_user_path_by_id($uid) . "/repos/" . $repo_name . ".git"; $r = rename($old_path, $new_path); if ($r !== TRUE) { rg_log("Cannot rename $old_path -> $new_path!"); break; } } // Now, make links from by_name if (!is_link($by_name)) { $by_id_rel = rg_repo_path_by_id_rel($uid, $repo_id); $r = symlink($by_id_rel, $by_name); if ($r !== TRUE) { rg_log("Cannot symlink $by_id_rel <- $by_name ($php_errormsg)!"); break; } } $ret = TRUE; break; } rg_log_exit(); return $ret; } /* * Reindex repos by id so we can rename repos easier. * And is more natural to index them by the unique id. */ function rg_fixes_repo_index_by_id($db) { rg_prof_start("fixes_repo_index_by_id"); rg_log_enter("fixes_repo_index_by_id"); $ret = FALSE; while (1) { $sql = "SELECT uid, repo_id, name FROM repos" . " WHERE git_dir_done > 0"; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; $all_repos_moved = TRUE; while (($row = rg_sql_fetch_array($res))) { $r = rg_fixes_repo_index_by_id_one($row['uid'], $row['repo_id'], $row['name']); if ($r !== TRUE) { $all_repos_moved = FALSE; break; } } rg_sql_free_result($res); if ($all_repos_moved !== TRUE) break; $ret = TRUE; break; } rg_log_exit(); rg_prof_end("fixes_repo_index_by_id"); return $ret; } /* * Index user by id and make links for names */ function rg_fixes_user_index_by_id_one($uid, $username) { global $php_errormsg; global $rg_repos; rg_log_enter("fixes_user_index_by_id_one: uid=$uid username=$username"); $ret = FALSE; while (1) { $user_path_uid = rg_user_path_by_id($uid); $user_path_name = rg_user_path_by_name($username); rg_log("user_path=[$user_path_uid][$user_path_name]"); // parend dir exits? if not, create it $p = dirname($user_path_uid); if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) { rg_log("cannot create parent dir [$p]"); break; } // parend dir exits? if not, create it $p = dirname($user_path_name); if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) { rg_log("cannot create parent dir [$p]"); break; } // We already moved it? if (!is_dir($user_path_uid)) { $x = $username . "_"; $old_path = $rg_repos . "/users/" . $x[0] . "/" . $x[1] . "/" . $username; if (!is_dir($old_path)) { $ret = TRUE; break; } $r = rename($old_path, $user_path_uid); if ($r !== TRUE) { rg_log("Cannot rename $old_path -> $user_path_uid!"); break; } } // Now, make links from name to id if (!is_link($user_path_name)) { $by_id_rel = rg_user_path_by_id_rel($uid); $r = symlink($by_id_rel, $user_path_name); if ($r !== TRUE) { rg_log("Cannot symlink $by_id_rel <- $user_path_name ($php_errormsg)!"); break; } } $ret = TRUE; break; } rg_log_exit(); return $ret; } /* * Reindex users by id so we can rename users easier. * And is more natural to index them by the unique id. */ function rg_fixes_user_index_by_id($db) { global $rg_repos; rg_prof_start("fixes_user_index_by_id"); rg_log_enter("fixes_user_index_by_id"); $ret = FALSE; while (1) { $sql = "SELECT uid, username FROM users"; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; $all_users_moved = TRUE; while (($row = rg_sql_fetch_array($res))) { $r = rg_fixes_user_index_by_id_one($row['uid'], $row['username']); if ($r !== TRUE) { $all_users_moved = FALSE; break; } } rg_sql_free_result($res); if ($all_users_moved !== TRUE) break; // Remove old structure dirs $r = rg_rmdir($rg_repos . "/users"); if ($r === FALSE) { rg_log("Cannot remove old structure dirs" . " (" . rg_util_error() . ")."); break; } $ret = TRUE; break; } rg_log_exit(); rg_prof_end("fixes_user_index_by_id"); return $ret; } /* * Move to the more generic webhooks structure */ function rg_fixes_wh_ver2($db) { global $rg_repos; rg_prof_start("fixes_wh_ver2"); rg_log_enter("fixes_wh_ver2"); $ret = FALSE; while (1) { $sql = "SELECT * FROM webhooks"; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; $all_fixed = TRUE; while (($row = rg_sql_fetch_array($res))) { $idata = array(); $idata['client_cert'] = $row['client_cert']; $idata['client_ca_cert'] = $row['client_ca_cert']; $idata['flags'] = $row['flags']; $idata['itype'] = $row['type']; $params = array( 'id' => $row['id'], 'idata' => serialize($idata) ); $sql = 'UPDATE webhooks SET idata = @@idata@@' . ' WHERE id = @@id@@'; $res2 = rg_sql_query_params($db, $sql, $params); rg_sql_free_result($res2); if ($res2 === FALSE) { $all_fixed = FALSE; break; } } rg_sql_free_result($res); if ($all_fixed !== TRUE) break; // Remove old fileds $all_good = TRUE; $a = array('client_cert', 'client_ca_cert', 'flags', 'type'); foreach ($a as $t) { $sql = 'ALTER TABLE webhooks DROP ' . $t; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_log('Could not drop ' . $t . '!'); $all_good = FALSE; break; } rg_sql_free_result($res); } if (!$all_good) break; $ret = TRUE; break; } rg_log_exit(); rg_prof_end("fixes_wh_ver2"); return $ret; } /* * Apply fixes */ function rg_fixes_run($db, $old_ver) { global $rg_fixes; global $rg_fixes_ver; rg_log("rg_fixes_run: old_ver=$old_ver..."); for ($i = $old_ver + 1; $i <= $rg_fixes_ver; $i++) { foreach ($rg_fixes[$i] as $function) { rg_log("Calling function $function..."); $r = $function($db); if ($r !== TRUE) { rg_log("Function $function returned error!"); return FALSE; } } } return TRUE; } /* * Tests if fixes are needed. * Returns FALSE on error, 0 if not needed, 1 if needed. */ function rg_fixes_needed($db) { global $rg_fixes_ver; rg_log_enter("fixes_needed"); $ret = FALSE; while (1) { $old = rg_state_get($db, "fixes_version"); if ($old === FALSE) break; if ($old === "") $old = 0; //rg_log("DEBUG: old=$old new=$rg_fixes_ver"); if ($old == $rg_fixes_ver) { // fixes are up to date $ret = 0; break; } $ret = 1; break; } rg_log_exit(); return $ret; } /* * Apply fixes if needed * Returns FALSE in case of error */ function rg_fixes_update($db) { global $rg_fixes_ver; rg_log_enter("fixes_update"); $ret = FALSE; while (1) { $old = rg_state_get($db, "fixes_version"); if ($old === FALSE) break; if ($old === "") $old = 0; if ($old == $rg_fixes_ver) { $ret = TRUE; break; } // If we cannot lock, return error if (rg_lock("fixes.lock") === FALSE) break; $r = rg_fixes_run($db, $old); if ($r !== TRUE) { rg_internal_error("Cannot apply fixes."); break; } $r = rg_state_set($db, "fixes_version", $rg_fixes_ver); if ($r !== TRUE) { rg_log("Cannot set state ver (" . rg_state_error() . ")"); break; } $ret = TRUE; break; } rg_unlock("fixes.lock"); rg_log_exit(); return $ret; } ?>