* @author Christopher Schäpers * @author Jakob Sack * @author Jörn Friedrich Dreyer * @author Morris Jobke * @author Oliver Kohl D.Sc. * @author Robin Appelman * @author Steffen Lindner * @author Thomas Müller * @author Vincent Petry * * @copyright Copyright (c) 2015, ownCloud, Inc. * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see * */ try { require_once 'lib/base.php'; if (\OCP\Util::needUpgrade()) { \OCP\Util::writeLog('cron', 'Update required, skipping cron', \OCP\Util::DEBUG); exit; } if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) { \OCP\Util::writeLog('cron', 'We are in maintenance mode, skipping cron', \OCP\Util::DEBUG); exit; } if (\OC::$server->getSystemConfig()->getValue('singleuser', false)) { \OCP\Util::writeLog('cron', 'We are in admin only mode, skipping cron', \OCP\Util::DEBUG); exit; } // load all apps to get all api routes properly setup OC_App::loadApps(); \OC::$server->getSession()->close(); // initialize a dummy memory session \OC::$server->setSession(new \OC\Session\Memory('')); $logger = \OC_Log::$object; // Don't do anything if ownCloud has not been installed if (!OC_Config::getValue('installed', false)) { exit(0); } \OC::$server->getTempManager()->cleanOld(); // Exit if background jobs are disabled! $appMode = \OCP\BackgroundJob::getExecutionType(); if ($appMode == 'none') { if (OC::$CLI) { echo 'Background Jobs are disabled!' . PHP_EOL; } else { OC_JSON::error(array('data' => array('message' => 'Background jobs disabled!'))); } exit(1); } if (OC::$CLI) { // set to run indefinitely if needed set_time_limit(0); // the cron job must be executed with the right user if (!OC_Util::runningOnWindows()) { if (!function_exists('posix_getuid')) { echo "The posix extensions are required - see http://php.net/manual/en/book.posix.php" . PHP_EOL; exit(0); } $user = posix_getpwuid(posix_getuid()); $configUser = posix_getpwuid(fileowner(OC::$SERVERROOT . '/config/config.php')); if ($user['name'] !== $configUser['name']) { echo "Console has to be executed with the same user as the web server is operated" . PHP_EOL; echo "Current user: " . $user['name'] . PHP_EOL; echo "Web server user: " . $configUser['name'] . PHP_EOL; exit(0); } } $config = OC::$server->getConfig(); $instanceId = $config->getSystemValue('instanceid'); $lockFileName = 'owncloud-server-' . $instanceId . '-cron.lock'; $lockDirectory = $config->getSystemValue('cron.lockfile.location', sys_get_temp_dir()); $lockDirectory = rtrim($lockDirectory, '\\/'); $lockFile = $lockDirectory . '/' . $lockFileName; if (!file_exists($lockFile)) { touch($lockFile); } // We call ownCloud from the CLI (aka cron) if ($appMode != 'cron') { \OCP\BackgroundJob::setExecutionType('cron'); } // open the file and try to lock if. If it is not locked, the background // job can be executed, otherwise another instance is already running $fp = fopen($lockFile, 'w'); $isLocked = flock($fp, LOCK_EX|LOCK_NB, $wouldBlock); // check if backgroundjobs is still running. The wouldBlock check is // needed on systems with advisory locking, see // http://php.net/manual/en/function.flock.php#45464 if (!$isLocked || $wouldBlock) { echo "Another instance of cron.php is still running!" . PHP_EOL; exit(1); } // Work $jobList = \OC::$server->getJobList(); $jobs = $jobList->getAll(); foreach ($jobs as $job) { $job->execute($jobList, $logger); } // unlock the file flock($fp, LOCK_UN); fclose($fp); } else { // We call cron.php from some website if ($appMode == 'cron') { // Cron is cron :-P OC_JSON::error(array('data' => array('message' => 'Backgroundjobs are using system cron!'))); } else { // Work and success :-) $jobList = \OC::$server->getJobList(); $job = $jobList->getNext(); if ($job != null) { $job->execute($jobList, $logger); $jobList->setLastJob($job); } OC_JSON::success(); } } // Log the successful cron execution if (\OC::$server->getConfig()->getSystemValue('cron_log', true)) { \OC::$server->getConfig()->setAppValue('core', 'lastcron', time()); } exit(); } catch (Exception $ex) { \OCP\Util::writeLog('cron', $ex->getMessage(), \OCP\Util::FATAL); } n38'>38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
// Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"io"
	"strings"

	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
)

// Tree represents a flat directory listing.
type Tree struct {
	ID         SHA1
	ResolvedID SHA1
	repo       *Repository

	gogitTree *object.Tree

	// parent tree
	ptree *Tree
}

// NewTree create a new tree according the repository and tree id
func NewTree(repo *Repository, id SHA1) *Tree {
	return &Tree{
		ID:   id,
		repo: repo,
	}
}

// SubTree get a sub tree by the sub dir path
func (t *Tree) SubTree(rpath string) (*Tree, error) {
	if len(rpath) == 0 {
		return t, nil
	}

	paths := strings.Split(rpath, "/")
	var (
		err error
		g   = t
		p   = t
		te  *TreeEntry
	)
	for _, name := range paths {
		te, err = p.GetTreeEntryByPath(name)
		if err != nil {
			return nil, err
		}

		g, err = t.repo.getTree(te.ID)
		if err != nil {
			return nil, err
		}
		g.ptree = p
		p = g
	}
	return g, nil
}

func (t *Tree) loadTreeObject() error {
	gogitTree, err := t.repo.gogitRepo.TreeObject(t.ID)
	if err != nil {
		return err
	}

	t.gogitTree = gogitTree
	return nil
}

// ListEntries returns all entries of current tree.
func (t *Tree) ListEntries() (Entries, error) {
	if t.gogitTree == nil {
		err := t.loadTreeObject()
		if err != nil {
			return nil, err
		}
	}

	entries := make([]*TreeEntry, len(t.gogitTree.Entries))
	for i, entry := range t.gogitTree.Entries {
		entries[i] = &TreeEntry{
			ID:             entry.Hash,
			gogitTreeEntry: &t.gogitTree.Entries[i],
			ptree:          t,
		}
	}

	return entries, nil
}

// ListEntriesRecursive returns all entries of current tree recursively including all subtrees
func (t *Tree) ListEntriesRecursive() (Entries, error) {
	if t.gogitTree == nil {
		err := t.loadTreeObject()
		if err != nil {
			return nil, err
		}
	}

	var entries []*TreeEntry
	seen := map[plumbing.Hash]bool{}
	walker := object.NewTreeWalker(t.gogitTree, true, seen)
	for {
		fullName, entry, err := walker.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		if seen[entry.Hash] {
			continue
		}

		convertedEntry := &TreeEntry{
			ID:             entry.Hash,
			gogitTreeEntry: &entry,
			ptree:          t,
			fullName:       fullName,
		}
		entries = append(entries, convertedEntry)
	}

	return entries, nil
}