-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathExportDestination.php
130 lines (116 loc) · 3.28 KB
/
ExportDestination.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\UserMigration;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\UserMigration\IExportDestination;
use OCP\UserMigration\UserMigrationException;
use ZipStreamer\COMPR;
use ZipStreamer\ZipStreamer;
class ExportDestination implements IExportDestination {
public const EXPORT_FILENAME = 'user.nextcloud_export';
protected ZipStreamer $streamer;
protected string $path;
/**
* @param resource $r resource to write the export into
*/
public function __construct($r, string $path) {
$this->streamer = new ZipStreamer(
[
'outstream' => $r,
'zip64' => true,
'compress' => COMPR::STORE,
'level' => COMPR::NONE,
]
);
$this->path = $path;
}
/**
* {@inheritDoc}
*/
public function addFileContents(string $path, string $content): void {
try {
$stream = fopen('php://temp', 'r+');
fwrite($stream, $content);
rewind($stream);
if ($this->streamer->addFileFromStream($stream, $path) !== true) {
throw new UserMigrationException();
}
} catch (\Throwable $e) {
throw new UserMigrationException("Failed to add content in $path in archive", 0, $e);
}
}
/**
* {@inheritDoc}
*/
public function addFileAsStream(string $path, $stream): void {
try {
if ($this->streamer->addFileFromStream($stream, $path) !== true) {
throw new UserMigrationException();
}
} catch (\Throwable $e) {
throw new UserMigrationException("Failed to add content from stream in $path in archive", 0, $e);
}
}
/**
* {@inheritDoc}
*/
public function copyFolder(Folder $folder, string $destinationPath, ?callable $nodeFilter = null): void {
$success = $this->streamer->addEmptyDir($destinationPath, [
'timestamp' => $folder->getMTime(),
]);
if (!$success) {
throw new UserMigrationException("Failed to create folder $destinationPath in archive");
}
$nodes = $folder->getDirectoryListing();
foreach ($nodes as $node) {
if (($nodeFilter !== null) && !$nodeFilter($node)) {
continue;
}
if ($node instanceof File) {
if ($node->getName() === static::EXPORT_FILENAME) {
/* Skip previous user export file */
// FIXME only ignore root one using getPath()
continue;
}
$read = $node->fopen('rb');
$success = $this->streamer->addFileFromStream($read, $destinationPath . '/' . $node->getName(), [
'timestamp' => $node->getMTime(),
]);
if (!$success) {
throw new UserMigrationException('Failed to copy file into ' . $destinationPath . '/' . $node->getName() . ' in archive');
}
} elseif ($node instanceof Folder) {
$this->copyFolder($node, $destinationPath . '/' . $node->getName(), $nodeFilter);
} else {
// ignore unknown node type, shouldn't happen
continue;
}
}
}
/**
* {@inheritDoc}
*/
public function setMigratorVersions(array $versions): void {
$this->addFileContents('migrator_versions.json', json_encode($versions));
}
/**
* {@inheritDoc}
*/
public function close(): void {
$success = $this->streamer->finalize();
if (!$success) {
throw new UserMigrationException('Failed to close zip streamer');
}
}
/**
* {@inheritDoc}
*/
public function getPath(): string {
return $this->path;
}
}