Completed
Push — master ( ac6203...621618 )
by Roeland
10s
created

BackgroundScanner::scanOneFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 20
ccs 0
cts 15
cp 0
rs 9.4285
cc 3
eloc 12
nc 3
nop 2
crap 12
1
<?php
2
/**
3
 * Copyright (c) 2012 Bart Visscher <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file.
7
 */
8
9
namespace OCA\Files_Antivirus\BackgroundJob;
10
11
use OC\BackgroundJob\TimedJob;
12
use OCA\Files_Antivirus\AppConfig;
13
use OCA\Files_Antivirus\ItemFactory;
14
use OCA\Files_Antivirus\Scanner\ScannerFactory;
15
use OCP\Files\File;
16
use OCP\Files\IMimeTypeLoader;
17
use OCP\IDBConnection;
18
use OCP\Files\IRootFolder;
19
use OCP\ILogger;
20
use OCP\IUser;
21
use OCP\IUserManager;
22
23
class BackgroundScanner extends TimedJob {
24
25
	const BATCH_SIZE = 10;
26
27
	/** @var IRootFolder */
28
	protected $rootFolder;
29
30
	/** @var ScannerFactory */
31
	private $scannerFactory;
32
33
	/** @var  AppConfig  */
34
	private $appConfig;
35
36
	/** @var ILogger */
37
	protected $logger;
38
39
	/** @var IUserManager */
40
	protected $userManager;
41
42
	/** @var IDBConnection */
43
	protected $db;
44
45
	/** @var IMimeTypeLoader */
46
	protected $mimeTypeLoader;
47
48
	/** @var ItemFactory */
49
	protected $itemFactory;
50
51
	/**
52
	 * A constructor
53
	 *
54
	 * @param ScannerFactory $scannerFactory
55
	 * @param AppConfig $appConfig
56
	 * @param IRootFolder $rootFolder
57
	 * @param ILogger $logger
58
	 * @param IUserManager $userManager
59
	 * @param IDBConnection $db
60
	 * @param IMimeTypeLoader $mimeTypeLoader
61
	 * @param ItemFactory $itemFactory
62
	 */
63
	public function __construct(ScannerFactory $scannerFactory,
64
								AppConfig $appConfig,
65
								IRootFolder $rootFolder,
66
								ILogger $logger,
67
								IUserManager $userManager,
68
								IDBConnection $db,
69
								IMimeTypeLoader $mimeTypeLoader,
70
								ItemFactory $itemFactory
71
	){
72
		$this->rootFolder = $rootFolder;
73
		$this->scannerFactory = $scannerFactory;
74
		$this->appConfig = $appConfig;
75
		$this->logger = $logger;
76
		$this->userManager = $userManager;
77
		$this->db = $db;
78
		$this->mimeTypeLoader = $mimeTypeLoader;
79
		$this->itemFactory = $itemFactory;
80
81
		// Run once per 15 minutes
82
		$this->setInterval(60 * 15);
83
	}
84
	
85
	/**
86
	 * Background scanner main job
87
	 */
88
	public function run($args){
89
		// locate files that are not checked yet
90
		try {
91
			$result = $this->getFilesForScan();
92
		} catch(\Exception $e) {
93
			$this->logger->error( __METHOD__ . ', exception: ' . $e->getMessage(), ['app' => 'files_antivirus']);
94
			return;
95
		}
96
97
		$cnt = 0;
98
		while (($row = $result->fetch()) && $cnt < self::BATCH_SIZE) {
99
			try {
100
				$fileId = $row['fileid'];
101
				$userId = $row['user_id'];
102
				/** @var IUser $owner */
103
				$owner = $this->userManager->get($userId);
104
				if (!$owner instanceof IUser){
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
105
					continue;
106
				}
107
				$this->scanOneFile($owner, $fileId);
108
				// increased only for successfully scanned files
109
				$cnt = $cnt + 1;
110
			} catch (\Exception $e) {
111
				$this->logger->error( __METHOD__ . ', exception: ' . $e->getMessage(), ['app' => 'files_antivirus']);
112
			}
113
		}
114
	}
115
116
	protected function getFilesForScan(){
117
		$dirMimeTypeId = $this->mimeTypeLoader->getId('httpd/unix-directory');
118
119
		$qb = $this->db->getQueryBuilder();
120
121
		$sizeLimit = (int)$this->appConfig->getAvMaxFileSize();
122
		if ( $sizeLimit === -1 ){
123
			$sizeLimitExpr = $qb->expr()->neq('fc.size', $qb->expr()->literal('0'));
124
		} else {
125
			$sizeLimitExpr = $qb->expr()->andX(
126
				$qb->expr()->neq('fc.size', $qb->expr()->literal('0')),
127
				$qb->expr()->lt('fc.size', $qb->createNamedParameter($sizeLimit))
128
			);
129
		}
130
131
		$qb->select(['fc.fileid', 'mnt.user_id'])
132
			->from('filecache', 'fc')
133
			->leftJoin('fc', 'files_antivirus', 'fa', $qb->expr()->eq('fa.fileid', 'fc.fileid'))
134
			->innerJoin(
135
				'fc',
136
				'mounts',
137
				'mnt',
138
				$qb->expr()->andX(
139
					$qb->expr()->eq('fc.storage', 'mnt.storage_id')
140
				)
141
			)
142
			->where(
143
				$qb->expr()->neq('fc.mimetype', $qb->expr()->literal($dirMimeTypeId))
144
			)
145
			->andWhere(
146
				$qb->expr()->orX(
147
					$qb->expr()->isNull('fa.fileid'),
148
					$qb->expr()->gt('fc.mtime', 'fa.check_time')
149
				)
150
			)
151
			->andWhere(
152
				$qb->expr()->like('fc.path', $qb->expr()->literal('files/%'))
153
			)
154
			->andWhere( $sizeLimitExpr )
155
		;
156
		return $qb->execute();
157
	}
158
159
	/**
160
	 * @param IUser $owner
161
	 * @param int $fileId
162
	 */
163
	protected function scanOneFile(IUser $owner, $fileId){
164
		$userFolder = $this->rootFolder->getUserFolder($owner->getUID());
165
		$files = $userFolder->getById($fileId);
166
167
		if (count($files) === 0) {
168
			return;
169
		}
170
171
		/** @var File $file */
172
		$file = array_pop($files);
173
174
		if (!($file instanceof File)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
175
			return;
176
		}
177
178
		$item = $this->itemFactory->newItem($file);
179
		$scanner = $this->scannerFactory->getScanner();
180
		$status = $scanner->scan($item);
181
		$status->dispatch($item);
182
	}
183
}
184