<?php require_once($INC . "/util.inc.php"); require_once($INC . "/log.inc.php"); require_once($INC . "/sql.inc.php"); require_once($INC . "/user.inc.php"); require_once($INC . "/git.inc.php"); require_once($INC . "/rights.inc.php"); require_once($INC . "/prof.inc.php"); require_once($INC . "/events.inc.php"); $rg_repo_rights = array( "A" => "Admin", "F" => "Fetch", "P" => "Push", "H" => "Anonymous push", "S" => "Create annotated tag", "N" => "Modify annotated tag", "n" => "Delete annotated tag", "Y" => "Create un-annotated tag", "U" => "Modify un-annotated tag", "u" => "Delete un-annotated tag", "C" => "Create branch", "D" => "Delete branch", "O" => "Non fast-forwards", "M" => "Merge commits", "W" => "Bad whitespace" ); // What rights are on by default // TODO: this should go into conf file? $rg_repo_rights_default = "FMH"; rg_rights_register("repo", $rg_repo_rights); // Repo history categories define('REPO_CAT_CREATE', 1); define('REPO_CAT_CLONED', 2); define('REPO_CAT_PUSH', 3); define('REPO_CAT_RENAME', 4); define('REPO_CAT_BUG_ADDED', 10); define('REPO_CAT_BUG_CLOSED', 11); $rg_repo_error = ""; function rg_repo_set_error($str) { global $rg_repo_error; $rg_repo_error = $str; } function rg_repo_error() { global $rg_repo_error; return $rg_repo_error; } /* * Events functions */ $rg_repo_functions = array( 3000 => "rg_repo_event_new", 3001 => "rg_repo_event_del", 3002 => "rg_repo_event_update", 3003 => "rg_repo_event_notify_user", 3004 => "rg_repo_event_symlink_by_name", 3005 => "rg_repo_event_storage_create" ); rg_event_register_functions($rg_repo_functions); /* * Event for adding a new repo */ function rg_repo_event_new($db, $event) { $ret = array(); $event['op'] = "new"; // Create git dir $x = $event; $x['category'] = 3005; $x['prio'] = 20; $x['notification'] .= "-git"; $ret[] = $x; // make symlink by name $x = $event; $x['category'] = 3004; $x['prio'] = 200; $x['notification'] .= "-symlink"; $ret[] = $x; // notify user $x = $event; $x['category'] = 3003; $x['prio'] = 100; $x['notification'] .= "-notify"; $ret[] = $x; // TODO: notify watchers return $ret; } /* * Event for deleting repo */ function rg_repo_event_del($db, $event) { $ret = array(); $event['op'] = "del"; // notify user $ret[] = array_merge($event, array("category" => 3003, "prio" => 100)); // TODO: notify watchers return $ret; } /* * Make a symlink by name (by_name/name -> ../by_id/xx/xx/xx/xx/xxxxxxxx.git) */ function rg_repo_event_symlink_by_name($db, $e) { rg_prof_start("repo_event_symlink_by_name"); $id_path = rg_repo_path_by_id($e['ui.uid'], $e['ri.repo_id']); $id_path_rel = rg_repo_path_by_id_rel($e['ui.uid'], $e['ri.repo_id']); $new_path = rg_repo_path_by_name($e['ui.uid'], $e['ri.name']); $ret = FALSE; rg_repo_set_error("internal error"); // TODO: we should do this everywhere? do { // Check if we already did the rename if (file_exists($new_path)) { if (!is_link($new_path)) { rg_internal_error("$new_path is not a link!"); break; } $v = readlink($new_path); if ($v === FALSE) { rg_internal_error("Cannot read link $new_path!"); break; } rg_log("new_path points to [$v]"); if (strcmp($id_path_rel, $v) == 0) { // Link already done $ret = array(); break; } // Seems that new_path points to other place $r = rename($new_path, $new_path . ".BOGUS." . time()); if ($r !== TRUE) { rg_internal_error("Cannot rename bogus!"); break; } } // Create links' parent $new_path_parent = dirname($new_path); if (!is_dir($new_path_parent)) { $r = mkdir($new_path_parent, 0755, TRUE); if ($r === FALSE) { rg_repo_set_error("cannot create links' parent"); break; } } // Now, the new name is free, do the link $r = symlink($id_path_rel, $new_path); if ($r !== TRUE) { rg_internal_error("Cannot symlink $id_path -> $new_path ($php_errormsg)!"); break; } $ret = array(); } while (0); rg_prof_end("repo_event_symlink_by_name"); return $ret; } /* * Creates git dir storage */ function rg_repo_event_storage_create($db, $e) { rg_prof_start("repo_event_storage_create"); rg_log("repo_event_storage_create: e=" . rg_array2string($e)); $ret = FALSE; do { $by_id_path = rg_repo_path_by_id($e['ui.uid'], $e['ri.repo_id']); if (!is_dir($by_id_path)) { if (mkdir($by_id_path, 0755, TRUE) === FALSE) { rg_repo_set_error("could not create folder $dst"); break; } } if ($e['ri.master'] == 0) { $r = rg_git_init($by_id_path); if ($r === FALSE) { rg_repo_set_error("cannot init master" . " (" . rg_git_error() . ")"); break; } } else { $mi = rg_repo_info($db, $e['ri.master'], 0, ""); if ($mi['exists'] != 1) { rg_repo_set_error("cannot find master (" . rg_repo_error() . ")"); break; } $master_by_id_path = rg_repo_path_by_id($mi['uid'], $mi['repo_id']); $r = rg_git_clone($master_by_id_path, $by_id_path); if ($r === FALSE) { rg_repo_set_error("could not create repo (" . rg_git_error() . ")"); break; } } $r = rg_repo_event_symlink_by_name($db, $e); if ($r === FALSE) break; $r = rg_repo_git_done($db, $e['ri.repo_id']); if ($r !== TRUE) break; $ret = array(); } while (0); return $ret; rg_prof_end("repo_event_storage_create"); return array(); } /* * Event for renaming a repo */ function rg_repo_event_update($db, $event) { $ret = array(); $event['op'] = "update"; // make symlink by name $ret[] = array_merge($event, array("category" => 3004, "prio" => 200)); // notify user $ret[] = array_merge($event, array("category" => 3003, "prio" => 100)); // TODO: notify watchers return $ret; } /* * User notification */ function rg_repo_event_notify_user($db, $event) { rg_prof_start("repo_event_notify_user"); $r = rg_mail("mail/user/repo/" . $event['op'], $event); if ($r === FALSE) return FALSE; rg_prof_end("repo_event_notify_user"); return array(); } /* * Inserts an event into repo_history table */ function rg_repo_history_insert($db, $repo_id, $category, $message) { rg_prof_start("repo_history_insert"); rg_log("repo_history_insert: repo_id=$repo_id, category=$category" . ", message=$message"); $ret = FALSE; do { $now = time(); $e_message = rg_sql_escape($db, $message); $sql = "INSERT INTO repo_history_" . gmdate("Y_m", $now) . " (itime, repo_id, category, message)" . " VALUES ($now, $repo_id, $category, '$e_message')"; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; rg_sql_free_result($res); $ret = TRUE; } while (0); rg_prof_end("repo_history_insert"); return $ret; } /* * Returns last events from repo_history * @category: 0 for any * @number: number of entries * @max_seconds: limit the search to less than max_seconds in the past */ function rg_repo_history_load($db, $repo_id, $category, $number, $max_seconds) { rg_prof_start("repo_history_load"); rg_log("repo_history_load: repo_id=$repo_id, category=$category" . ", number=$number max_seconds=$max_seconds"); $ret = FALSE; do { $now = time(); $category_sql = ""; if ($category > 0) $category_sql = " AND category = " . $category; $limit_sql = ""; if ($number > 0) $limit_sql = " LIMIT " . $number; else $limit_sql = " LIMIT 100"; $time_sql = ""; if ($max_seconds > 0) $time_sql = " AND itime >= " . ($now - $max_seconds); $sql = "SELECT * FROM repo_history" . " WHERE repo_id = $repo_id" . $category_sql . $time_sql . " ORDER BY itime DESC" . $limit_sql; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; $ret = array(); while (($row = rg_sql_fetch_array($res))) { $row['itime_text'] = gmdate("Y-m-d H:i", $row['itime']); $ret[] = $row; } rg_sql_free_result($res); } while (0); rg_prof_end("repo_history_load"); return $ret; } /* * Enforce name */ function rg_repo_ok($repo) { global $rg_repo_allow; global $rg_repo_min_len; global $rg_repo_max_len; if (empty($repo)) { rg_repo_set_error("Invalid repository name (empty)"); return FALSE; } if (rg_chars_allow($repo, $rg_repo_allow) === FALSE) { rg_repo_set_error("Invalid repository name (invalid chars)"); return FALSE; } if (preg_match('/\.\./', $repo) > 0) { rg_repo_set_error("Invalid repository name (..)"); return FALSE; } if (strlen($repo) < $rg_repo_min_len) { rg_repo_set_error("repository name is too short" . " (minimum $rg_repo_min_len)"); return FALSE; } if (strlen($repo) > $rg_repo_max_len) { rg_repo_set_error("repository name is too long" . " (maximum $rg_repo_max_len)"); return FALSE; } return TRUE; } /* * Returns the relative path to a repository based on id */ function rg_repo_path_by_id_rel($uid, $repo_id) { return "../by_id/" . $repo_id . ".git"; } /* * Returns the path to a repository based on id */ function rg_repo_path_by_id($uid, $repo_id) { return rg_user_path_by_id($uid) . "/repos/by_id/" . $repo_id . ".git"; } /* * Returns the path to a repository based on name */ function rg_repo_path_by_name($uid, $repo_name) { return rg_user_path_by_id($uid) . "/repos/by_name/" . $repo_name . ".git"; } $rg_repo_info_cache = array(); function rg_repo_invalidate_cache($uid, $repo_id) { global $rg_repo_info_cache; $key = $uid . " " . $repo_id; if (isset($rg_repo_info_cache[$key])) unset($rg_repo_info_cache[$key]); //rg_log_ml("DEBUG: rg_repo_info_cache: " . print_r($rg_repo_info_cache, TRUE)); } /* * Return info about a repo * If you want to lookup by repo_id or uid/repo_name */ function rg_repo_info($db, $repo_id, $uid, $repo_name) { global $rg_repo_info_cache; rg_prof_start("repo_info"); rg_log("repo_info: repo_id=$repo_id uid=$uid repo_name=$repo_name."); $ret['ok'] = 0; $ret['exists'] = 0; do { if ($repo_id > 0) { $key = $repo_id; if (isset($rg_repo_info_cache[$key])) { $ret = $rg_repo_info_cache[$key]; $ret['from_cache'] = 1; break; } } if ($repo_id > 0) { $add = " AND repo_id = $repo_id"; } else if (!empty($repo_name)) { $e_repo = rg_sql_escape($db, $repo_name); $add = " AND uid = $uid AND name = '$e_repo'"; } else { rg_repo_set_error("no repo_id or user/repo specified!"); break; } $sql = "SELECT * FROM repos WHERE 1 = 1" . $add; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("cannot query (" . rg_sql_error() . ")"); break; } $ret['ok'] = 1; $rows = rg_sql_num_rows($res); if ($rows > 0) $ret = rg_sql_fetch_array($res); rg_sql_free_result($res); if (($rows == 0) && ($repo_id == 0)) { // Repo not found, maybe it was renamed $_repo_id = rg_repo_lookup_by_old_name($db, $uid, $repo_name); if (($_repo_id === FALSE) || ($_repo_id == 0)) { rg_log("\tRepo not found!"); break; } $ret = rg_repo_info($db, $_repo_id, 0, ""); break; } // small fixes if ($rows > 0) $ret['HTML:description'] = nl2br($ret['description']); $ret['exists'] = 1; $ret['ok'] = 1; } while (0); if (($repo_id > 0) && !isset($ret['from_cache'])) $rg_repo_info_cache[$key] = $ret; rg_prof_end("repo_info"); return $ret; } /* * Check if a user has access to repository */ function rg_repo_allow($db, $ri, $ui, $needed_rights) { rg_prof_start("repo_allow"); rg_log("repo_allow: repo_id=" . $ri['repo_id'] . " uid=" . $ui['uid'] . ", needed_rights=$needed_rights..."); if ($ui['is_admin'] == 1) { rg_log("\tUser is admin, allow!"); return TRUE; } if (empty($needed_rights)) { rg_log("\tNo perms passed!"); return FALSE; } // anonymous acess (git://...) if ($ui['uid'] == 0) { $db_rights = $ri['default_rights']; } else { $rr = rg_repo_rights_get($db, $ri, $ui['uid'], 0); if ($rr['ok'] != 1) { rg_repo_set_error("cannot get rights from db"); return FALSE; } $db_rights = $rr['rights']; } rg_log("\tdb rights: " . $db_rights); if (rg_rights_allow($db_rights, $needed_rights) !== TRUE) { rg_repo_set_error("no rights ($needed_rights) vs ($db_rights)"); return FALSE; } rg_log("\tAllow access!"); rg_prof_end("repo_allow"); return TRUE; } /* * Add a repository * @master - makes sense only for clones: who is the master repo. * TODO: put all fields into an array! * TODO: unify this function with rg_repo_update. */ function rg_repo_create($db, $master, $ui, $name, $max_commit_size, $description, $rights, $max_users) { rg_prof_start("repo_create"); // TODO: reorder parameters - are not logical rg_log("repo_create: uid=" . $ui['uid'] . ", name=[$name], master=$master" . ", max_commit_size=$max_commit_size" . ", description=[$description]" . ", rights=$rights, max_users=$max_users..."); // TODO: test if user is allowed to add a repository $ret = FALSE; do { if (rg_repo_ok($name) === FALSE) break; // First, test if it already exists $ri = rg_repo_info($db, 0, $ui['uid'], $name); if ($ri['ok'] != 1) break; if ($ri['exists'] == 1) { rg_repo_set_error("Repository already exists."); break; } $e_name = rg_sql_escape($db, $name); $description = trim($description); $e_description = rg_sql_escape($db, $description); $itime = time(); $sql = "INSERT INTO repos (uid, master, name" . ", itime, max_commit_size, description, git_dir_done" . ", default_rights, max_users)" . " VALUES (" . $ui['uid'] . ", $master, '$e_name'" . ", $itime, $max_commit_size, '$e_description', 0" . ", '$rights', $max_users)" . " RETURNING repo_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot insert (" . rg_sql_error() . ")"); break; } $row = rg_sql_fetch_array($res); rg_sql_free_result($res); $event = array("category" => 3000, "prio" => 50, "notification" => "repo_create-" . $ui['uid'] . "-" . $row['repo_id'], "ui.uid" => $ui['uid'], "ui.email" => $ui['email'], "ri.name" => $name, "ri.master" => $master, "ri.description" => $description, "ri.rights_text" => rg_implode("\t", rg_rights_text("repo", $rights), "\n"), "ri.repo_id" => $row['repo_id'], "ri.url" => rg_base_url() . rg_re_repopage($ui, $name), "IP" => rg_var_str("REMOTE_ADDR")); $r = rg_event_add($db, $event); if ($r !== TRUE) { rg_repo_set_error("cannot add event" . " (" . rg_event_error() . ")"); break; } // TODO: This will go with events rg_repo_history_insert($db, $row['repo_id'], REPO_CAT_CREATE, "Repo " . $name . " created."); $ret = $row['repo_id']; } while (0); rg_prof_end("repo_create"); return $ret; } /* * Delete a repo */ function rg_repo_delete($db, $repo_id, $ui) { rg_prof_start("repo_delete"); rg_log("repo_delete: uid=" . $ui['uid'] . ", repo_id=$repo_id"); $ret = FALSE; do { // TODO: Check rights // TODO: Transaction? // Only mark it as such, deletion will happen in background $sql = "UPDATE repos SET deleted = 1 WHERE repo_id = $repo_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot delete (" . rg_sql_error() . ")"); break; } rg_sql_free_result($res); $event = array("category" => 3001, "prio" => 50, "IP" => rg_var_str("REMOTE_ADDR"), "ui.email" => $ui['email'], "ri.name" => $name, "ri.repo_id" => $repo_id); $r = rg_event_add($db, $event); if ($r !== TRUE) { rg_repo_set_error("cannot add event" . " (" . rg_event_error() . ")"); break; } $ret = TRUE; } while (0); rg_prof_end("repo_delete"); return $ret; } /* * Lookup in db the old names, so we can redirect the user to the new name */ function rg_repo_lookup_by_old_name($db, $uid, $old_name) { rg_prof_start("rg_repo_lookup_by_old_name"); rg_log("repo_lookup_by_old_name: uid=$uid old_name=$old_name"); $ret = FALSE; do { $e_old_name = rg_sql_escape($db, $old_name); $sql = "SELECT repo_id FROM repos_renames" . " WHERE uid = " . $uid . " AND old_name = '$e_old_name'"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("cannot lookup old name (" . rg_sql_error() . ")"); break; } $rows = rg_sql_num_rows($res); if ($rows > 0) $row = rg_sql_fetch_array($res); rg_sql_free_result($res); if ($rows == 0) $ret = 0; else $ret = $row['repo_id']; } while (0); rg_prof_end("rg_repo_lookup_by_old_name"); return $ret; } /* * Add a rename to the database */ function rg_repo_insert_rename($db, $uid, $repo_id, $old_name) { rg_prof_start("repo_insert_rename"); rg_log("repo_insert_rename: uid=$uid repo_id=$repo_id old_name=$old_name"); $ret = FALSE; do { $e_old_name = rg_sql_escape($db, $old_name); // Check if already exists in the database $r = rg_repo_lookup_by_old_name($db, $uid, $old_name); if ($r === FALSE) break; if ($r > 0) { $sql = "UPDATE repos_renames" . " SET repo_id = $repo_id" . " WHERE uid = " . $uid . " AND old_name = '$e_old_name'"; } else { $now = time(); $sql = "INSERT INTO repos_renames (uid, old_name" . ", repo_id, itime)" . " VALUES (" . $uid . ", '$e_old_name'" . ", " . $repo_id . ", $now" . ")"; } $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("cannot link with old_name in db" . " (" . rg_sql_error() . ")"); break; } $ret = TRUE; } while (0); rg_prof_end("repo_insert_rename"); return $ret; } /* * Updates a repository * @login_ui - info of the user doing the update. * Warning, it may not be the owner. * TODO: check rights - also for create? */ function rg_repo_update($db, $login_ui, &$new) { rg_prof_start("repo_update"); rg_log("repo_update: login_uid=" . $login_ui['uid'] . " new=" . rg_array2string($new)); $ret = FALSE; rg_repo_set_error(""); // TODO: should we do this anywhere? do { if (rg_repo_ok($new['name']) !== TRUE) break; // TODO: Something is strange here, why we need to lookup the repo?! // First, test if it already exists $ri = rg_repo_info($db, $new['repo_id'], $login_ui['uid'], $new['name']); if ($ri['ok'] != 1) break; if (($ri['exists'] == 1) && ($ri['repo_id'] != $new['repo_id'])) { rg_repo_set_error("Name already taken."); break; } // Second, test if repo_id is valid $ri = rg_repo_info($db, $new['repo_id'], $login_ui['uid'], ""); if ($ri['ok'] != 1) break; if ($ri['exists'] == 0) { rg_repo_set_error("Repo " . $new['repo_id'] . " does not exists."); break; } // Check if the user renamed the repo $renamed = 0; if (strcmp($new['name'], $ri['name']) != 0) { $renamed = 1; $r = rg_repo_insert_rename($db, $login_ui['uid'], $new['repo_id'], $ri['name']); if ($r !== TRUE) break; } $e_name = rg_sql_escape($db, $new['name']); $new['description'] = trim($new['description']); $e_description = rg_sql_escape($db, $new['description']); $sql = "UPDATE repos SET name = '$e_name'" . ", max_commit_size = " . $new['max_commit_size'] . ", description = '$e_description'" . ", default_rights = '" . $new['default_rights'] . "'" . ", max_users = " . $new['max_users'] . " WHERE repo_id = " . $new['repo_id']; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot update (" . rg_sql_error() . ")"); break; } rg_sql_free_result($res); $event = array("category" => 3002, "prio" => 50, "ui.uid" => $login_ui['uid'], "ui.email" => $login_ui['email'], "ri.url" => rg_base_url() . rg_re_repopage($login_ui, $new['name']), "IP" => rg_var_str("REMOTE_ADDR")); $event = rg_array_merge($event, "ri.old", $ri); $event = rg_array_merge($event, "ri", $new); $event['ri.old.description_md5'] = md5($ri['description']); $event['ri.description_md5'] = md5($new['description']); $event['ri.rights_text'] = rg_implode("\t", rg_rights_text("repo", $new['default_rights']), "\n"); $r = rg_event_add($db, $event); if ($r !== TRUE) { rg_repo_set_error("cannot add event" . " (" . rg_event_error() . ")"); break; } $ret = array("renamed" => $renamed); } while (0); rg_prof_end("repo_update"); return $ret; } /* * List repositories */ function rg_repo_list_query($db, $url, $sql) { rg_prof_start("repo_list_query"); rg_log("repo_list_query: url=$url, sql=$sql..."); $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("cannot list by query (" . rg_sql_error() . ")"); return FALSE; } $d = array(); while (($row = rg_sql_fetch_array($res))) { $_line = array(); foreach ($row as $k => $v) $_line[$k] = $v; $_ui = rg_user_info($db, $row['uid'], "", ""); if ($_ui['exists'] != 1) { rg_repo_set_error("user associated with this repo not found"); return FALSE; } $_line['owner'] = $_ui['username']; $_line['url_repo'] = rg_re_repopage($_ui, $row['name']); $_line['url_user'] = rg_re_userpage($_ui); $_line['HTML:description'] = nl2br($row['description']); $master_repo = "-"; if ($row['master'] > 0) { $master_repo = "?"; $_mi = rg_repo_info($db, $row['master'], 0, ""); if ($_mi['exists'] = 1) $master_repo = $_mi['name']; } $_line['clone_of'] = $master_repo; $_line['creation'] = gmdate("Y-m-d", $row['itime']); // rights $_line['rights'] = implode(", ", rg_rights_text("repo", $row['default_rights'])); $_max = "unlimited"; if ($row['disk_quota_mb'] > 0) $_max = rg_1024($row['disk_quota_mb'] * 1024 * 1024); $_line['disk_used'] = $row['disk_used_mb'] . "/" . $_max; $_line['max_commit_size'] = "unlimited"; if ($row['max_commit_size'] > 0) $_line['max_commit_size'] = rg_1024($row['max_commit_size']); $_line['max_users'] = "unlimited"; if ($row['max_users'] > 0) $_line['max_users'] = $row['max_users']; $d[] = $_line; } rg_sql_free_result($res); rg_prof_end("repo_list_query"); return rg_template_table("repo/list", $d, array()); } /* * List repos of user 'ui'. */ function rg_repo_list($db, $url, $ui) { rg_log("repo_list: url=$url, uid=" . $ui['uid']); $add = ""; if ($ui['uid'] > 0) $add = " AND uid = " . $ui['uid']; $sql = "SELECT * FROM repos" . " WHERE deleted = 0" . $add . " ORDER BY name"; return rg_repo_list_query($db, $url, $sql); } /* * Search in all repositories owned by 'ui' or public * We need to exclude private repositories. */ function rg_repo_search($db, $ui, $q) { rg_prof_start("repo_search"); rg_log("repo_search: q=$q..."); $e_q = rg_sql_escape($db, $q); $sql = "SELECT * FROM repos" . " WHERE deleted = 0" . " AND (name ILIKE '%$e_q%' OR description ILIKE '%$e_q%')" . " AND (uid = " . $ui['uid'] . " OR default_rights LIKE '%F%'" . " OR " . $ui['admin'] . " = 1)" . " ORDER BY master, name" . " LIMIT 10"; $r = rg_repo_list_query($db, "", $sql); rg_prof_end("repo_search"); return $r; } /* * Computes the size of a repository */ function rg_repo_disk_mb($path) { rg_log("repo_disk_mb: path=$path..."); // TODO return 10; } /* * Mark a git repo as done */ function rg_repo_git_done($db, $repo_id) { rg_prof_start("repo_git_done"); rg_log("repo_git_done: repo_id=$repo_id..."); $ret = FALSE; do { $sql = "UPDATE repos SET git_dir_done = 1" . " WHERE repo_id = $repo_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot query (" . rg_sql_error() . ")"); break; } rg_sql_free_result($res); $ret = TRUE; } while (0); rg_prof_end("repo_git_done"); return $ret; } /* * Get rights for a user */ function rg_repo_rights_get($db, $ri, $uid, $flags) { rg_prof_start("repo_rights_get"); rg_log("rg_repo_rights_get: repo_id=" . $ri['repo_id'] . ", uid=$uid" . " flags=$flags..."); $ret = array(); $ret['ok'] = 0; $ret['rights'] = ""; $repo_id = $ri['repo_id']; // Give all rights to owner if ($ri['uid'] == $uid) { rg_log("\tuid $uid is the owner."); $rights = rg_rights_all("repo"); if (($flags & RG_RIGHTS_FILL_EXISTS) == 0) { rg_log("\tNo need to fill 'exists' field. Return."); $ret['rights'] = $rights; $ret['ok'] = 1; return $ret; } } else { rg_log("\tuid $uid is NOT the owner (" . $ri['uid'] . ");" . " assign default rights."); $rights = $ri['default_rights']; } $r = rg_rights_get($db, "repo", $repo_id, $uid); if ($r['ok'] !== 1) { rg_repo_set_error("cannot get rights (" . rg_rights_error() . ")!"); return FALSE; } $ret['rights'] = rg_rights_combine($rights, $r['rights']); rg_log("\tFinal rights($rights + " . $r['rights'] . ")=" . $ret['rights']); $ret['ok'] = 1; rg_prof_end("repo_rights_get"); return $ret; } /* * Add rights for a repo */ function rg_repo_rights_set($db, $ri, $uid, $rights) { if (!isset($ri['repo_id'])) { rg_internal_error("repo_id is not defined!"); return FALSE; } rg_log("rg_repo_rights_set: repo_id=" . $ri['repo_id'] . ", uid=$uid, rights=$rights..."); $r = rg_rights_set($db, "repo", $ri['repo_id'], $uid, $rights); if ($r !== TRUE) { rg_repo_set_error("cannot alter rights (" . rg_rights_error() . ")!"); return FALSE; } return TRUE; } /* * List rights for a repo */ function rg_repo_rights_load($db, $ri) { rg_log("rg_repo_rights_load: repo_id=" . $ri['repo_id']); $r = rg_rights_load($db, "repo", $ri['repo_id']); if ($r === FALSE) { rg_repo_set_error("Cannot list rights (" . rg_rights_error() . ")"); return FALSE; } return $r; } /* * Returns TRUE if a repo is over limit */ function rg_repo_over_limit($ri) { if ($ri['disk_quota_mb'] == 0) return FALSE; if ($ri['disk_used_mb'] >= $ri['disk_quota_mb']) return TRUE; return FALSE; } /* * Add in queue a statistic file */ function rg_repo_stats_push2file($a) { global $rg_state_dir; $q = $rg_state_dir . "/qstats"; if (!is_dir($q)) { $r = @mkdir($q, 0700); if ($r !== TRUE) { rg_internal_error("Cannot create dir $q ($php_errormsg)!"); return FALSE; } } $buf = serialize($a); $file = sha1($buf); $r = file_put_contents($q . "/" . $file, $buf); if ($r === FALSE) { rg_internal_error("Cannot store file in qstats ($php_errormsg)!"); return FALSE; } return $file; } ?>