These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /** |
||
6 | * balloon |
||
7 | * |
||
8 | * @copyright Copryright (c) 2012-2019 gyselroth GmbH (https://gyselroth.com) |
||
9 | * @license GPL-3.0 https://opensource.org/licenses/GPL-3.0 |
||
10 | */ |
||
11 | |||
12 | namespace Balloon\Async; |
||
13 | |||
14 | use Balloon\Filesystem\Node\Collection; |
||
15 | use Balloon\Filesystem\Node\File; |
||
16 | use Balloon\Filesystem\Node\NodeInterface; |
||
17 | use Balloon\Filesystem\Storage\Adapter\Blackhole; |
||
18 | use Balloon\Filesystem\Storage\Adapter\Smb; |
||
19 | use Balloon\Helper; |
||
20 | use Balloon\Server; |
||
21 | use Balloon\Server\User; |
||
22 | use Icewind\SMB\Exception\NotFoundException; |
||
23 | use Icewind\SMB\IFileInfo; |
||
24 | use Icewind\SMB\INotifyHandler; |
||
25 | use Icewind\SMB\IShare; |
||
26 | use MongoDB\BSON\UTCDateTime; |
||
27 | use Normalizer; |
||
28 | use Psr\Log\LoggerInterface; |
||
29 | use TaskScheduler\AbstractJob; |
||
30 | |||
31 | class SmbScanner extends AbstractJob |
||
32 | { |
||
33 | /** |
||
34 | * Server. |
||
35 | * |
||
36 | * @var Server |
||
37 | */ |
||
38 | protected $server; |
||
39 | |||
40 | /** |
||
41 | * Logger. |
||
42 | * |
||
43 | * @var LoggerInterface |
||
44 | */ |
||
45 | protected $logger; |
||
46 | |||
47 | /** |
||
48 | * Constructor. |
||
49 | */ |
||
50 | public function __construct(Server $server, LoggerInterface $logger) |
||
51 | { |
||
52 | $this->server = $server; |
||
53 | $this->logger = $logger; |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * {@inheritdoc} |
||
58 | */ |
||
59 | public function start(): bool |
||
60 | { |
||
61 | $dummy = new Blackhole(); |
||
62 | $fs = $this->server->getFilesystem(); |
||
63 | $mount = $collection = $fs->findNodeById($this->data['id']); |
||
64 | $user = $this->server->getUserById($collection->getOwner()); |
||
65 | $user_fs = $user->getFilesystem(); |
||
66 | $smb = $collection->getStorage(); |
||
67 | $share = $smb->getShare(); |
||
68 | $action = INotifyHandler::NOTIFY_ADDED; |
||
69 | |||
70 | if (isset($this->data['action'])) { |
||
71 | $action = $this->data['action']; |
||
72 | } |
||
73 | |||
74 | $collection |
||
75 | ->setFilesystem($user_fs) |
||
76 | ->setStorage($dummy); |
||
77 | |||
78 | $path = $smb->getRoot(); |
||
79 | if (isset($this->data['path'])) { |
||
80 | $path = $this->data['path']; |
||
81 | } |
||
82 | |||
83 | if ($path === '' || $path === '.') { |
||
84 | $path = DIRECTORY_SEPARATOR; |
||
85 | } |
||
86 | |||
87 | if ($path !== DIRECTORY_SEPARATOR) { |
||
88 | $parent_path = dirname($path); |
||
89 | if ($path !== '.') { |
||
90 | $collection = $this->getParent($collection, $share, $parent_path, $action); |
||
91 | $collection->setStorage($dummy); |
||
92 | } |
||
93 | } |
||
94 | |||
95 | $recursive = true; |
||
96 | if (isset($this->data['recursive'])) { |
||
97 | $recursive = $this->data['recursive']; |
||
98 | } |
||
99 | |||
100 | $this->recursiveIterator($collection, $mount, $share, $dummy, $user, $smb, $path, $recursive, $action); |
||
101 | |||
102 | return true; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Get parent node from sub path. |
||
107 | */ |
||
108 | protected function getParent(Collection $mount, IShare $share, string $path, int $action): Collection |
||
109 | { |
||
110 | $parent = $mount; |
||
111 | $nodes = explode(DIRECTORY_SEPARATOR, $path); |
||
112 | $sub = ''; |
||
113 | $dummy = $mount->getStorage(); |
||
114 | |||
115 | foreach ($nodes as $child) { |
||
116 | if ($child === '.') { |
||
117 | continue; |
||
118 | } |
||
119 | |||
120 | try { |
||
121 | $sub .= DIRECTORY_SEPARATOR.$child; |
||
122 | $parent = $parent->getChild($child); |
||
123 | $parent->setStorage($dummy); |
||
124 | } catch (\Exception $e) { |
||
125 | if ($action === INotifyHandler::NOTIFY_REMOVED) { |
||
126 | throw $e; |
||
127 | } |
||
128 | $this->logger->debug('child node ['.$child.'] does not exits, add folder', [ |
||
129 | 'category' => get_class($this), |
||
130 | 'exception' => $e, |
||
131 | ]); |
||
132 | |||
133 | $node = $share->stat($sub); |
||
134 | $parent = $parent->addDirectory($child, $this->getAttributes($mount, $share, $node)); |
||
135 | } |
||
136 | } |
||
137 | |||
138 | return $parent; |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Delete node. |
||
143 | */ |
||
144 | protected function deleteNode(NodeInterface $node, Blackhole $dummy): bool |
||
145 | { |
||
146 | if ($node instanceof Collection) { |
||
147 | $node->doRecursiveAction(function (NodeInterface $node) use ($dummy) { |
||
148 | if ($node instanceof Collection) { |
||
149 | $node->setStorage($dummy); |
||
150 | } |
||
151 | }); |
||
152 | } |
||
153 | |||
154 | $node->delete(true); |
||
155 | |||
156 | return true; |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Iterate recursively through smb share. |
||
161 | */ |
||
162 | protected function recursiveIterator(Collection $parent, Collection $mount, IShare $share, Blackhole $dummy, User $user, Smb $smb, string $path, bool $recursive, int $action): void |
||
163 | { |
||
164 | $this->logger->debug('sync smb path ['.$path.'] in mount ['.$mount->getId().'] from operation ['.$action.']', [ |
||
165 | 'category' => get_class($this), |
||
166 | 'recursive' => $recursive, |
||
167 | ]); |
||
168 | |||
169 | $system_path = $path.DIRECTORY_SEPARATOR.$smb->getSystemFolder(); |
||
170 | |||
171 | if ($path === $system_path) { |
||
172 | return; |
||
173 | } |
||
174 | |||
175 | try { |
||
176 | $node = $share->stat($path); |
||
177 | } catch (NotFoundException $e) { |
||
0 ignored issues
–
show
|
|||
178 | if ($action === INotifyHandler::NOTIFY_REMOVED) { |
||
179 | $node = $parent->getChild(Helper::mb_basename($path)); |
||
180 | $node->getParent()->setStorage($dummy); |
||
181 | $this->deleteNode($node, $dummy); |
||
182 | } |
||
183 | |||
184 | return; |
||
185 | } |
||
186 | |||
187 | if ($node->isDirectory()) { |
||
188 | $parent->setStorage($dummy); |
||
189 | |||
190 | if ($path === DIRECTORY_SEPARATOR) { |
||
191 | $child = $parent; |
||
192 | } else { |
||
193 | if ($parent->childExists($node->getName())) { |
||
194 | $child = $parent->getChild($node->getName()); |
||
195 | } else { |
||
196 | $child = $parent->addDirectory($node->getName(), $this->getAttributes($mount, $share, $node)); |
||
197 | } |
||
198 | } |
||
199 | |||
200 | if ($recursive === true) { |
||
201 | $child->setStorage($dummy); |
||
202 | $nodes = []; |
||
203 | |||
204 | foreach ($share->dir($path) as $node) { |
||
205 | if ($node->getPath() === $system_path) { |
||
206 | continue; |
||
207 | } |
||
208 | |||
209 | $nodes[] = $node->getName(); |
||
210 | $child_path = ($path === DIRECTORY_SEPARATOR) ? $path.$node->getName() : $path.DIRECTORY_SEPARATOR.$node->getName(); |
||
211 | |||
212 | try { |
||
213 | $this->recursiveIterator($child, $mount, $share, $dummy, $user, $smb, $child_path, $recursive, $action); |
||
214 | } catch (\Exception $e) { |
||
215 | $this->logger->error('failed sync child node ['.$child_path.'] in smb mount', [ |
||
216 | 'category' => get_class($this), |
||
217 | 'exception' => $e, |
||
218 | ]); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | foreach ($child->getChildren() as $sub_child) { |
||
223 | $sub_name = Normalizer::normalize($sub_child->getName()); |
||
224 | |||
225 | if (!in_array($sub_name, $nodes)) { |
||
226 | $this->deleteNode($sub_child, $dummy); |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | } else { |
||
231 | $this->syncFile($parent, $mount, $node, $action, $share, $user); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Sync file. |
||
237 | */ |
||
238 | protected function syncFile(Collection $parent, Collection $mount, IFileInfo $node, int $action, IShare $share, User $user): bool |
||
239 | { |
||
240 | $this->logger->debug('update smb file meta data from ['.$node->getPath().'] in parent node ['.$parent->getId().']', [ |
||
241 | 'category' => get_class($this), |
||
242 | ]); |
||
243 | |||
244 | $attributes = $this->getAttributes($mount, $share, $node); |
||
245 | |||
246 | if ($parent->childExists($node->getName())) { |
||
247 | $file = $parent->getChild($node->getName()); |
||
248 | $file->getParent()->setStorage($parent->getStorage()); |
||
249 | if ($this->fileUpdateRequired($file, $attributes)) { |
||
250 | $this->updateFileContent($parent, $share, $node, $file, $user, $attributes); |
||
251 | } |
||
252 | |||
253 | return true; |
||
254 | } |
||
255 | |||
256 | $file = $parent->addFile($node->getName(), null, $attributes); |
||
257 | $file->getParent()->setStorage($parent->getStorage()); |
||
258 | $this->updateFileContent($parent, $share, $node, $file, $user, $attributes); |
||
259 | |||
260 | return true; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Set file content. |
||
265 | */ |
||
266 | protected function updateFileContent(Collection $parent, IShare $share, IFileInfo $node, File $file, User $user, array $attributes): bool |
||
267 | { |
||
268 | $storage = $parent->getStorage(); |
||
269 | $stream = $share->read($node->getPath()); |
||
270 | $session = $storage->storeTemporaryFile($stream, $user); |
||
271 | $file->setContent($session, $attributes); |
||
272 | |||
273 | fclose($stream); |
||
274 | |||
275 | return true; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Check if file content needs to be updated. |
||
280 | */ |
||
281 | protected function fileUpdateRequired(File $file, array $smb_attributes): bool |
||
282 | { |
||
283 | $meta_attributes = $file->getAttributes(); |
||
284 | |||
285 | return $smb_attributes['size'] != $meta_attributes['size'] || $smb_attributes['changed'] != $meta_attributes['changed']; |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Prepare node attributes. |
||
290 | */ |
||
291 | protected function getAttributes(Collection $collection, IShare $share, IFileInfo $node): array |
||
292 | { |
||
293 | $stats = $share->stat($node->getPath()); |
||
294 | $mtime = new UTCDateTime($stats->getMTime() * 1000); |
||
295 | |||
296 | $attributes = [ |
||
297 | 'created' => $mtime, |
||
298 | 'changed' => $mtime, |
||
299 | 'storage_reference' => $collection->getId(), |
||
300 | 'storage' => [ |
||
301 | 'path' => '/'.ltrim($node->getPath(), '/'), |
||
302 | ], |
||
303 | ]; |
||
304 | |||
305 | if (!$node->isDirectory()) { |
||
306 | $attributes['size'] = $node->getSize(); |
||
307 | } |
||
308 | |||
309 | return $attributes; |
||
310 | } |
||
311 | } |
||
312 |
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.