gboudreau/Greyhole

View on GitHub
includes/CLI/CopyCliRunner.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php
/*
Copyright 2021 Guillaume Boudreau

This file is part of Greyhole.

Greyhole is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Greyhole 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Greyhole.  If not, see <http://www.gnu.org/licenses/>.
*/

require_once('includes/CLI/AbstractCliRunner.php');

class CopyCliRunner extends AbstractCliRunner {
    protected $source;
    protected $share_name;
    protected $target;

    public function run() {
        ConfigHelper::parse();
        DB::connect();
        Log::setAction(ACTION_INITIALIZE);
        Metastores::choose_metastores_backups();
        Log::setAction(ACTION_CP);
        Log::setLevel(Log::INFO);

        $argc = $GLOBALS['argc'];
        $argv = $GLOBALS['argv'];

        if (basename($argv[0]) == 'cpgh') {
            $num_required_args = 3;
        } else {
            $num_required_args = 4;
        }

        if ($argc != $num_required_args) {
            error_log(
                "\n"
                . "Usage: cpgh source share_name/target/dir/\n"
                . "       greyhole --cp source share_name/target/dir/\n"
                . "\n"
                . "Examples: cpgh \"Some Movie (2021)\" Videos/Movies/\n"
                . "          greyhole --cp \"Something Large\" Backups/\n"
                . "\n"
                . "`cpgh` is used to ADD files onto your Greyhole storage pool, without going through Samba.\n"
                . "\n"
                . "Instead of copying the files into a Samba share, and letting the Greyhole daemon then\n"
                . "  move the files into one of your storage pool drives, this command will copy the SOURCE\n"
                . "  files directly into a storage pool drive.\n"
                . "  It will also create extra copies of those files, if the TARGET share is configured with\n"
                . "  num_copies > 1.\n"
            );
            exit(1);
        }

        $source = $argv[$num_required_args-2];
        $target = $argv[$num_required_args-1];

        if (!file_exists($source)) {
            error_log("cpgh: cannot access '$source': No such file or directory");
            if (getenv('IN_DOCKER')) {
                error_log("\nNote that since you are using Docker, the 'source' file/folder needs to be accessible within the Docker container.");
            }
            exit(2);
        }

        $target = explode('/', $target);
        $share_name = array_shift($target);
        $target = implode('/', $target) . '/' . basename($source);
        if (is_dir($source)) {
            $target .= '/';
        }

        if (!SharesConfig::exists($share_name)) {
            error_log("cpgh: target '$share_name' is not a valid Samba/Greyhole share.");
            exit(3);
        }

        echo "Source" . (is_dir($source) ? ' (folder)' : '') . ": $source\n";
        echo "Target share: $share_name\n";
        echo "Target in share: $target\n";

        $this->source = $source;
        $this->share_name = $share_name;
        $this->target = $target;

        // No need to check for locks, since we copy the files
        Config::set(CONFIG_CHECK_FOR_OPEN_FILES, FALSE);

        if (is_dir($source)) {
            static::glob_dir($source);
        } else {
            static::copy_file($source);
        }
    }

    protected function copy_file($file) {
        $file = clean_dir($file);
        $target_full_path = $this->target . str_replace($this->source, '', $file);
        $target_full_path = clean_dir(trim($target_full_path, '/'));
        $t = new WriteTask(
            [
                'id'              => 0,
                'action'          => 'write',
                'share'           => $this->share_name,
                'full_path'       => $target_full_path,
                'additional_info' => 'source:' . $file,
                'complete'        => 'yes',
                'event_date'      => date('Y-m-d H:i:s'),
            ]
        );
        echo "\n";
        $t->execute();
    }

    protected function glob_dir($dir) {
        $dir = new DirectoryIterator($dir);
        foreach ($dir as $fileinfo) {
            if ($fileinfo->isDot()) {
                continue;
            }
            $file = $fileinfo->getPathname();
            if ($fileinfo->isDir()) {
                static::glob_dir($file);
            } else {
                static::copy_file($file);
            }
        }
    }
}

?>