Completed
Pull Request — stable10 (#5729)
by Lukas
46:36 queued 29:32
created
lib/private/Files/Config/UserMountCache.php 4 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -206,7 +206,7 @@
 block discarded – undo
206 206
 	}
207 207
 
208 208
 	/**
209
-	 * @param $fileId
209
+	 * @param integer $fileId
210 210
 	 * @return array
211 211
 	 * @throws \OCP\Files\NotFoundException
212 212
 	 */
Please login to merge, or discard this patch.
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -22,8 +22,6 @@
 block discarded – undo
22 22
 
23 23
 namespace OC\Files\Config;
24 24
 
25
-use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
26
-use OC\Files\Filesystem;
27 25
 use OCA\Files_Sharing\SharedMount;
28 26
 use OCP\DB\QueryBuilder\IQueryBuilder;
29 27
 use OCP\Files\Config\ICachedMountInfo;
Please login to merge, or discard this patch.
Indentation   +281 added lines, -281 removed lines patch added patch discarded remove patch
@@ -43,285 +43,285 @@
 block discarded – undo
43 43
  * Cache mounts points per user in the cache so we can easilly look them up
44 44
  */
45 45
 class UserMountCache implements IUserMountCache {
46
-	/**
47
-	 * @var IDBConnection
48
-	 */
49
-	private $connection;
50
-
51
-	/**
52
-	 * @var IUserManager
53
-	 */
54
-	private $userManager;
55
-
56
-	/**
57
-	 * Cached mount info.
58
-	 * Map of $userId to ICachedMountInfo.
59
-	 *
60
-	 * @var ICache
61
-	 **/
62
-	private $mountsForUsers;
63
-
64
-	/**
65
-	 * @var ILogger
66
-	 */
67
-	private $logger;
68
-
69
-	/**
70
-	 * @var ICache
71
-	 */
72
-	private $cacheInfoCache;
73
-
74
-	/**
75
-	 * UserMountCache constructor.
76
-	 *
77
-	 * @param IDBConnection $connection
78
-	 * @param IUserManager $userManager
79
-	 * @param ILogger $logger
80
-	 */
81
-	public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
-		$this->connection = $connection;
83
-		$this->userManager = $userManager;
84
-		$this->logger = $logger;
85
-		$this->cacheInfoCache = new CappedMemoryCache();
86
-		$this->mountsForUsers = new CappedMemoryCache();
87
-	}
88
-
89
-	public function registerMounts(IUser $user, array $mounts) {
90
-		// filter out non-proper storages coming from unit tests
91
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
92
-			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
-		});
94
-		/** @var ICachedMountInfo[] $newMounts */
95
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
-			if ($mount->getStorageRootId() === -1) {
98
-				return null;
99
-			} else {
100
-				return new LazyStorageMountInfo($user, $mount);
101
-			}
102
-		}, $mounts);
103
-		$newMounts = array_values(array_filter($newMounts));
104
-
105
-		$cachedMounts = $this->getMountsForUser($user);
106
-		$mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
107
-			// since we are only looking for mounts for a specific user comparing on root id is enough
108
-			return $mount1->getRootId() - $mount2->getRootId();
109
-		};
110
-
111
-		/** @var ICachedMountInfo[] $addedMounts */
112
-		$addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
113
-		/** @var ICachedMountInfo[] $removedMounts */
114
-		$removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
115
-
116
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
117
-
118
-		foreach ($addedMounts as $mount) {
119
-			$this->addToCache($mount);
120
-			$this->mountsForUsers[$user->getUID()][] = $mount;
121
-		}
122
-		foreach ($removedMounts as $mount) {
123
-			$this->removeFromCache($mount);
124
-			$index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
125
-			unset($this->mountsForUsers[$user->getUID()][$index]);
126
-		}
127
-		foreach ($changedMounts as $mount) {
128
-			$this->updateCachedMount($mount);
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * @param ICachedMountInfo[] $newMounts
134
-	 * @param ICachedMountInfo[] $cachedMounts
135
-	 * @return ICachedMountInfo[]
136
-	 */
137
-	private function findChangedMounts(array $newMounts, array $cachedMounts) {
138
-		$changed = [];
139
-		foreach ($newMounts as $newMount) {
140
-			foreach ($cachedMounts as $cachedMount) {
141
-				if (
142
-					$newMount->getRootId() === $cachedMount->getRootId() &&
143
-					($newMount->getMountPoint() !== $cachedMount->getMountPoint() || $newMount->getMountId() !== $cachedMount->getMountId())
144
-				) {
145
-					$changed[] = $newMount;
146
-				}
147
-			}
148
-		}
149
-		return $changed;
150
-	}
151
-
152
-	private function addToCache(ICachedMountInfo $mount) {
153
-		if ($mount->getStorageId() !== -1) {
154
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
155
-				'storage_id' => $mount->getStorageId(),
156
-				'root_id' => $mount->getRootId(),
157
-				'user_id' => $mount->getUser()->getUID(),
158
-				'mount_point' => $mount->getMountPoint(),
159
-				'mount_id' => $mount->getMountId()
160
-			], ['root_id', 'user_id']);
161
-		} else {
162
-			// in some cases this is legitimate, like orphaned shares
163
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
164
-		}
165
-	}
166
-
167
-	private function updateCachedMount(ICachedMountInfo $mount) {
168
-		$builder = $this->connection->getQueryBuilder();
169
-
170
-		$query = $builder->update('mounts')
171
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
172
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
173
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
174
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
175
-
176
-		$query->execute();
177
-	}
178
-
179
-	private function removeFromCache(ICachedMountInfo $mount) {
180
-		$builder = $this->connection->getQueryBuilder();
181
-
182
-		$query = $builder->delete('mounts')
183
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
184
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
185
-		$query->execute();
186
-	}
187
-
188
-	private function dbRowToMountInfo(array $row) {
189
-		$user = $this->userManager->get($row['user_id']);
190
-		if (is_null($user)) {
191
-			return null;
192
-		}
193
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id']);
194
-	}
195
-
196
-	/**
197
-	 * @param IUser $user
198
-	 * @return ICachedMountInfo[]
199
-	 */
200
-	public function getMountsForUser(IUser $user) {
201
-		if (!isset($this->mountsForUsers[$user->getUID()])) {
202
-			$builder = $this->connection->getQueryBuilder();
203
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
204
-				->from('mounts')
205
-				->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
206
-
207
-			$rows = $query->execute()->fetchAll();
208
-
209
-			$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
210
-		}
211
-		return $this->mountsForUsers[$user->getUID()];
212
-	}
213
-
214
-	/**
215
-	 * @param int $numericStorageId
216
-	 * @return CachedMountInfo[]
217
-	 */
218
-	public function getMountsForStorageId($numericStorageId) {
219
-		$builder = $this->connection->getQueryBuilder();
220
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
221
-			->from('mounts')
222
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
223
-
224
-		$rows = $query->execute()->fetchAll();
225
-
226
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
227
-	}
228
-
229
-	/**
230
-	 * @param int $rootFileId
231
-	 * @return CachedMountInfo[]
232
-	 */
233
-	public function getMountsForRootId($rootFileId) {
234
-		$builder = $this->connection->getQueryBuilder();
235
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
236
-			->from('mounts')
237
-			->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
238
-
239
-		$rows = $query->execute()->fetchAll();
240
-
241
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
242
-	}
243
-
244
-	/**
245
-	 * @param $fileId
246
-	 * @return array
247
-	 * @throws \OCP\Files\NotFoundException
248
-	 */
249
-	private function getCacheInfoFromFileId($fileId) {
250
-		if (!isset($this->cacheInfoCache[$fileId])) {
251
-			$builder = $this->connection->getQueryBuilder();
252
-			$query = $builder->select('storage', 'path')
253
-				->from('filecache')
254
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
255
-
256
-			$row = $query->execute()->fetch();
257
-			if (is_array($row)) {
258
-				$this->cacheInfoCache[$fileId] = [
259
-					(int)$row['storage'],
260
-					$row['path']
261
-				];
262
-			} else {
263
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
264
-			}
265
-		}
266
-		return $this->cacheInfoCache[$fileId];
267
-	}
268
-
269
-	/**
270
-	 * @param int $fileId
271
-	 * @return ICachedMountInfo[]
272
-	 * @since 9.0.0
273
-	 */
274
-	public function getMountsForFileId($fileId) {
275
-		try {
276
-			list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
277
-		} catch (NotFoundException $e) {
278
-			return [];
279
-		}
280
-		$mountsForStorage = $this->getMountsForStorageId($storageId);
281
-
282
-		// filter mounts that are from the same storage but a different directory
283
-		return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
284
-			if ($fileId === $mount->getRootId()) {
285
-				return true;
286
-			}
287
-			try {
288
-				list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId());
289
-			} catch (NotFoundException $e) {
290
-				return false;
291
-			}
292
-
293
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
294
-		});
295
-
296
-	}
297
-
298
-	/**
299
-	 * Remove all cached mounts for a user
300
-	 *
301
-	 * @param IUser $user
302
-	 */
303
-	public function removeUserMounts(IUser $user) {
304
-		$builder = $this->connection->getQueryBuilder();
305
-
306
-		$query = $builder->delete('mounts')
307
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
308
-		$query->execute();
309
-	}
310
-
311
-	public function removeUserStorageMount($storageId, $userId) {
312
-		$builder = $this->connection->getQueryBuilder();
313
-
314
-		$query = $builder->delete('mounts')
315
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
316
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
317
-		$query->execute();
318
-	}
319
-
320
-	public function remoteStorageMounts($storageId) {
321
-		$builder = $this->connection->getQueryBuilder();
322
-
323
-		$query = $builder->delete('mounts')
324
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
325
-		$query->execute();
326
-	}
46
+    /**
47
+     * @var IDBConnection
48
+     */
49
+    private $connection;
50
+
51
+    /**
52
+     * @var IUserManager
53
+     */
54
+    private $userManager;
55
+
56
+    /**
57
+     * Cached mount info.
58
+     * Map of $userId to ICachedMountInfo.
59
+     *
60
+     * @var ICache
61
+     **/
62
+    private $mountsForUsers;
63
+
64
+    /**
65
+     * @var ILogger
66
+     */
67
+    private $logger;
68
+
69
+    /**
70
+     * @var ICache
71
+     */
72
+    private $cacheInfoCache;
73
+
74
+    /**
75
+     * UserMountCache constructor.
76
+     *
77
+     * @param IDBConnection $connection
78
+     * @param IUserManager $userManager
79
+     * @param ILogger $logger
80
+     */
81
+    public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
+        $this->connection = $connection;
83
+        $this->userManager = $userManager;
84
+        $this->logger = $logger;
85
+        $this->cacheInfoCache = new CappedMemoryCache();
86
+        $this->mountsForUsers = new CappedMemoryCache();
87
+    }
88
+
89
+    public function registerMounts(IUser $user, array $mounts) {
90
+        // filter out non-proper storages coming from unit tests
91
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
92
+            return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
+        });
94
+        /** @var ICachedMountInfo[] $newMounts */
95
+        $newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
+            if ($mount->getStorageRootId() === -1) {
98
+                return null;
99
+            } else {
100
+                return new LazyStorageMountInfo($user, $mount);
101
+            }
102
+        }, $mounts);
103
+        $newMounts = array_values(array_filter($newMounts));
104
+
105
+        $cachedMounts = $this->getMountsForUser($user);
106
+        $mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
107
+            // since we are only looking for mounts for a specific user comparing on root id is enough
108
+            return $mount1->getRootId() - $mount2->getRootId();
109
+        };
110
+
111
+        /** @var ICachedMountInfo[] $addedMounts */
112
+        $addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
113
+        /** @var ICachedMountInfo[] $removedMounts */
114
+        $removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
115
+
116
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
117
+
118
+        foreach ($addedMounts as $mount) {
119
+            $this->addToCache($mount);
120
+            $this->mountsForUsers[$user->getUID()][] = $mount;
121
+        }
122
+        foreach ($removedMounts as $mount) {
123
+            $this->removeFromCache($mount);
124
+            $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
125
+            unset($this->mountsForUsers[$user->getUID()][$index]);
126
+        }
127
+        foreach ($changedMounts as $mount) {
128
+            $this->updateCachedMount($mount);
129
+        }
130
+    }
131
+
132
+    /**
133
+     * @param ICachedMountInfo[] $newMounts
134
+     * @param ICachedMountInfo[] $cachedMounts
135
+     * @return ICachedMountInfo[]
136
+     */
137
+    private function findChangedMounts(array $newMounts, array $cachedMounts) {
138
+        $changed = [];
139
+        foreach ($newMounts as $newMount) {
140
+            foreach ($cachedMounts as $cachedMount) {
141
+                if (
142
+                    $newMount->getRootId() === $cachedMount->getRootId() &&
143
+                    ($newMount->getMountPoint() !== $cachedMount->getMountPoint() || $newMount->getMountId() !== $cachedMount->getMountId())
144
+                ) {
145
+                    $changed[] = $newMount;
146
+                }
147
+            }
148
+        }
149
+        return $changed;
150
+    }
151
+
152
+    private function addToCache(ICachedMountInfo $mount) {
153
+        if ($mount->getStorageId() !== -1) {
154
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
155
+                'storage_id' => $mount->getStorageId(),
156
+                'root_id' => $mount->getRootId(),
157
+                'user_id' => $mount->getUser()->getUID(),
158
+                'mount_point' => $mount->getMountPoint(),
159
+                'mount_id' => $mount->getMountId()
160
+            ], ['root_id', 'user_id']);
161
+        } else {
162
+            // in some cases this is legitimate, like orphaned shares
163
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
164
+        }
165
+    }
166
+
167
+    private function updateCachedMount(ICachedMountInfo $mount) {
168
+        $builder = $this->connection->getQueryBuilder();
169
+
170
+        $query = $builder->update('mounts')
171
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
172
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
173
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
174
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
175
+
176
+        $query->execute();
177
+    }
178
+
179
+    private function removeFromCache(ICachedMountInfo $mount) {
180
+        $builder = $this->connection->getQueryBuilder();
181
+
182
+        $query = $builder->delete('mounts')
183
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
184
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
185
+        $query->execute();
186
+    }
187
+
188
+    private function dbRowToMountInfo(array $row) {
189
+        $user = $this->userManager->get($row['user_id']);
190
+        if (is_null($user)) {
191
+            return null;
192
+        }
193
+        return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id']);
194
+    }
195
+
196
+    /**
197
+     * @param IUser $user
198
+     * @return ICachedMountInfo[]
199
+     */
200
+    public function getMountsForUser(IUser $user) {
201
+        if (!isset($this->mountsForUsers[$user->getUID()])) {
202
+            $builder = $this->connection->getQueryBuilder();
203
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
204
+                ->from('mounts')
205
+                ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
206
+
207
+            $rows = $query->execute()->fetchAll();
208
+
209
+            $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
210
+        }
211
+        return $this->mountsForUsers[$user->getUID()];
212
+    }
213
+
214
+    /**
215
+     * @param int $numericStorageId
216
+     * @return CachedMountInfo[]
217
+     */
218
+    public function getMountsForStorageId($numericStorageId) {
219
+        $builder = $this->connection->getQueryBuilder();
220
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
221
+            ->from('mounts')
222
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
223
+
224
+        $rows = $query->execute()->fetchAll();
225
+
226
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
227
+    }
228
+
229
+    /**
230
+     * @param int $rootFileId
231
+     * @return CachedMountInfo[]
232
+     */
233
+    public function getMountsForRootId($rootFileId) {
234
+        $builder = $this->connection->getQueryBuilder();
235
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
236
+            ->from('mounts')
237
+            ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
238
+
239
+        $rows = $query->execute()->fetchAll();
240
+
241
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
242
+    }
243
+
244
+    /**
245
+     * @param $fileId
246
+     * @return array
247
+     * @throws \OCP\Files\NotFoundException
248
+     */
249
+    private function getCacheInfoFromFileId($fileId) {
250
+        if (!isset($this->cacheInfoCache[$fileId])) {
251
+            $builder = $this->connection->getQueryBuilder();
252
+            $query = $builder->select('storage', 'path')
253
+                ->from('filecache')
254
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
255
+
256
+            $row = $query->execute()->fetch();
257
+            if (is_array($row)) {
258
+                $this->cacheInfoCache[$fileId] = [
259
+                    (int)$row['storage'],
260
+                    $row['path']
261
+                ];
262
+            } else {
263
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
264
+            }
265
+        }
266
+        return $this->cacheInfoCache[$fileId];
267
+    }
268
+
269
+    /**
270
+     * @param int $fileId
271
+     * @return ICachedMountInfo[]
272
+     * @since 9.0.0
273
+     */
274
+    public function getMountsForFileId($fileId) {
275
+        try {
276
+            list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
277
+        } catch (NotFoundException $e) {
278
+            return [];
279
+        }
280
+        $mountsForStorage = $this->getMountsForStorageId($storageId);
281
+
282
+        // filter mounts that are from the same storage but a different directory
283
+        return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
284
+            if ($fileId === $mount->getRootId()) {
285
+                return true;
286
+            }
287
+            try {
288
+                list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId());
289
+            } catch (NotFoundException $e) {
290
+                return false;
291
+            }
292
+
293
+            return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
294
+        });
295
+
296
+    }
297
+
298
+    /**
299
+     * Remove all cached mounts for a user
300
+     *
301
+     * @param IUser $user
302
+     */
303
+    public function removeUserMounts(IUser $user) {
304
+        $builder = $this->connection->getQueryBuilder();
305
+
306
+        $query = $builder->delete('mounts')
307
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
308
+        $query->execute();
309
+    }
310
+
311
+    public function removeUserStorageMount($storageId, $userId) {
312
+        $builder = $this->connection->getQueryBuilder();
313
+
314
+        $query = $builder->delete('mounts')
315
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
316
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
317
+        $query->execute();
318
+    }
319
+
320
+    public function remoteStorageMounts($storageId) {
321
+        $builder = $this->connection->getQueryBuilder();
322
+
323
+        $query = $builder->delete('mounts')
324
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
325
+        $query->execute();
326
+    }
327 327
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -88,11 +88,11 @@  discard block
 block discarded – undo
88 88
 
89 89
 	public function registerMounts(IUser $user, array $mounts) {
90 90
 		// filter out non-proper storages coming from unit tests
91
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
91
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
92 92
 			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93 93
 		});
94 94
 		/** @var ICachedMountInfo[] $newMounts */
95
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
95
+		$newMounts = array_map(function(IMountPoint $mount) use ($user) {
96 96
 			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97 97
 			if ($mount->getStorageRootId() === -1) {
98 98
 				return null;
@@ -103,7 +103,7 @@  discard block
 block discarded – undo
103 103
 		$newMounts = array_values(array_filter($newMounts));
104 104
 
105 105
 		$cachedMounts = $this->getMountsForUser($user);
106
-		$mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
106
+		$mountDiff = function(ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
107 107
 			// since we are only looking for mounts for a specific user comparing on root id is enough
108 108
 			return $mount1->getRootId() - $mount2->getRootId();
109 109
 		};
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 			], ['root_id', 'user_id']);
161 161
 		} else {
162 162
 			// in some cases this is legitimate, like orphaned shares
163
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
163
+			$this->logger->debug('Could not get storage info for mount at '.$mount->getMountPoint());
164 164
 		}
165 165
 	}
166 166
 
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 		if (is_null($user)) {
191 191
 			return null;
192 192
 		}
193
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id']);
193
+		return new CachedMountInfo($user, (int) $row['storage_id'], (int) $row['root_id'], $row['mount_point'], $row['mount_id']);
194 194
 	}
195 195
 
196 196
 	/**
@@ -256,11 +256,11 @@  discard block
 block discarded – undo
256 256
 			$row = $query->execute()->fetch();
257 257
 			if (is_array($row)) {
258 258
 				$this->cacheInfoCache[$fileId] = [
259
-					(int)$row['storage'],
259
+					(int) $row['storage'],
260 260
 					$row['path']
261 261
 				];
262 262
 			} else {
263
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
263
+				throw new NotFoundException('File with id "'.$fileId.'" not found');
264 264
 			}
265 265
 		}
266 266
 		return $this->cacheInfoCache[$fileId];
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
 		$mountsForStorage = $this->getMountsForStorageId($storageId);
281 281
 
282 282
 		// filter mounts that are from the same storage but a different directory
283
-		return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
283
+		return array_filter($mountsForStorage, function(ICachedMountInfo $mount) use ($internalPath, $fileId) {
284 284
 			if ($fileId === $mount->getRootId()) {
285 285
 				return true;
286 286
 			}
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
 				return false;
291 291
 			}
292 292
 
293
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
293
+			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath.'/';
294 294
 		});
295 295
 
296 296
 	}
Please login to merge, or discard this patch.
lib/private/Files/Filesystem.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -62,7 +62,6 @@
 block discarded – undo
62 62
 use OC\Files\Mount\MountPoint;
63 63
 use OC\Files\Storage\StorageFactory;
64 64
 use OCP\Files\Config\IMountProvider;
65
-use OCP\Files\Mount\IMountPoint;
66 65
 use OCP\Files\NotFoundException;
67 66
 use OCP\IUserManager;
68 67
 
Please login to merge, or discard this patch.
Doc Comments   +28 added lines, -2 removed lines patch added patch discarded remove patch
@@ -338,6 +338,9 @@  discard block
 block discarded – undo
338 338
 		}
339 339
 	}
340 340
 
341
+	/**
342
+	 * @param string $root
343
+	 */
341 344
 	static public function init($user, $root) {
342 345
 		if (self::$defaultInstance) {
343 346
 			return false;
@@ -521,7 +524,7 @@  discard block
 block discarded – undo
521 524
 	/**
522 525
 	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
523 526
 	 *
524
-	 * @param \OC\Files\Storage\Storage|string $class
527
+	 * @param string $class
525 528
 	 * @param array $arguments
526 529
 	 * @param string $mountpoint
527 530
 	 */
@@ -653,6 +656,9 @@  discard block
 block discarded – undo
653 656
 		return self::$defaultInstance->is_dir($path);
654 657
 	}
655 658
 
659
+	/**
660
+	 * @param string $path
661
+	 */
656 662
 	static public function is_file($path) {
657 663
 		return self::$defaultInstance->is_file($path);
658 664
 	}
@@ -665,6 +671,9 @@  discard block
 block discarded – undo
665 671
 		return self::$defaultInstance->filetype($path);
666 672
 	}
667 673
 
674
+	/**
675
+	 * @param string $path
676
+	 */
668 677
 	static public function filesize($path) {
669 678
 		return self::$defaultInstance->filesize($path);
670 679
 	}
@@ -677,6 +686,9 @@  discard block
 block discarded – undo
677 686
 		return self::$defaultInstance->isCreatable($path);
678 687
 	}
679 688
 
689
+	/**
690
+	 * @param string $path
691
+	 */
680 692
 	static public function isReadable($path) {
681 693
 		return self::$defaultInstance->isReadable($path);
682 694
 	}
@@ -689,6 +701,9 @@  discard block
 block discarded – undo
689 701
 		return self::$defaultInstance->isDeletable($path);
690 702
 	}
691 703
 
704
+	/**
705
+	 * @param string $path
706
+	 */
692 707
 	static public function isSharable($path) {
693 708
 		return self::$defaultInstance->isSharable($path);
694 709
 	}
@@ -706,6 +721,7 @@  discard block
 block discarded – undo
706 721
 	}
707 722
 
708 723
 	/**
724
+	 * @param string $path
709 725
 	 * @return string
710 726
 	 */
711 727
 	static public function file_get_contents($path) {
@@ -728,6 +744,10 @@  discard block
 block discarded – undo
728 744
 		return self::$defaultInstance->copy($path1, $path2);
729 745
 	}
730 746
 
747
+	/**
748
+	 * @param string $path
749
+	 * @param string $mode
750
+	 */
731 751
 	static public function fopen($path, $mode) {
732 752
 		return self::$defaultInstance->fopen($path, $mode);
733 753
 	}
@@ -743,6 +763,9 @@  discard block
 block discarded – undo
743 763
 		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
744 764
 	}
745 765
 
766
+	/**
767
+	 * @param string $path
768
+	 */
746 769
 	static public function getMimeType($path) {
747 770
 		return self::$defaultInstance->getMimeType($path);
748 771
 	}
@@ -755,6 +778,9 @@  discard block
 block discarded – undo
755 778
 		return self::$defaultInstance->free_space($path);
756 779
 	}
757 780
 
781
+	/**
782
+	 * @param string $query
783
+	 */
758 784
 	static public function search($query) {
759 785
 		return self::$defaultInstance->search($query);
760 786
 	}
@@ -868,7 +894,7 @@  discard block
 block discarded – undo
868 894
 	 * @param string $path
869 895
 	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
870 896
 	 * defaults to true
871
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
897
+	 * @return \OCP\Files\FileInfo|null False if file does not exist
872 898
 	 */
873 899
 	public static function getFileInfo($path, $includeMountPoints = true) {
874 900
 		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
Please login to merge, or discard this patch.
Indentation   +833 added lines, -833 removed lines patch added patch discarded remove patch
@@ -69,837 +69,837 @@
 block discarded – undo
69 69
 
70 70
 class Filesystem {
71 71
 
72
-	/**
73
-	 * @var Mount\Manager $mounts
74
-	 */
75
-	private static $mounts;
76
-
77
-	public static $loaded = false;
78
-	/**
79
-	 * @var \OC\Files\View $defaultInstance
80
-	 */
81
-	static private $defaultInstance;
82
-
83
-	static private $usersSetup = array();
84
-
85
-	static private $normalizedPathCache = null;
86
-
87
-	static private $listeningForProviders = false;
88
-
89
-	/**
90
-	 * classname which used for hooks handling
91
-	 * used as signalclass in OC_Hooks::emit()
92
-	 */
93
-	const CLASSNAME = 'OC_Filesystem';
94
-
95
-	/**
96
-	 * signalname emitted before file renaming
97
-	 *
98
-	 * @param string $oldpath
99
-	 * @param string $newpath
100
-	 */
101
-	const signal_rename = 'rename';
102
-
103
-	/**
104
-	 * signal emitted after file renaming
105
-	 *
106
-	 * @param string $oldpath
107
-	 * @param string $newpath
108
-	 */
109
-	const signal_post_rename = 'post_rename';
110
-
111
-	/**
112
-	 * signal emitted before file/dir creation
113
-	 *
114
-	 * @param string $path
115
-	 * @param bool $run changing this flag to false in hook handler will cancel event
116
-	 */
117
-	const signal_create = 'create';
118
-
119
-	/**
120
-	 * signal emitted after file/dir creation
121
-	 *
122
-	 * @param string $path
123
-	 * @param bool $run changing this flag to false in hook handler will cancel event
124
-	 */
125
-	const signal_post_create = 'post_create';
126
-
127
-	/**
128
-	 * signal emits before file/dir copy
129
-	 *
130
-	 * @param string $oldpath
131
-	 * @param string $newpath
132
-	 * @param bool $run changing this flag to false in hook handler will cancel event
133
-	 */
134
-	const signal_copy = 'copy';
135
-
136
-	/**
137
-	 * signal emits after file/dir copy
138
-	 *
139
-	 * @param string $oldpath
140
-	 * @param string $newpath
141
-	 */
142
-	const signal_post_copy = 'post_copy';
143
-
144
-	/**
145
-	 * signal emits before file/dir save
146
-	 *
147
-	 * @param string $path
148
-	 * @param bool $run changing this flag to false in hook handler will cancel event
149
-	 */
150
-	const signal_write = 'write';
151
-
152
-	/**
153
-	 * signal emits after file/dir save
154
-	 *
155
-	 * @param string $path
156
-	 */
157
-	const signal_post_write = 'post_write';
158
-
159
-	/**
160
-	 * signal emitted before file/dir update
161
-	 *
162
-	 * @param string $path
163
-	 * @param bool $run changing this flag to false in hook handler will cancel event
164
-	 */
165
-	const signal_update = 'update';
166
-
167
-	/**
168
-	 * signal emitted after file/dir update
169
-	 *
170
-	 * @param string $path
171
-	 * @param bool $run changing this flag to false in hook handler will cancel event
172
-	 */
173
-	const signal_post_update = 'post_update';
174
-
175
-	/**
176
-	 * signal emits when reading file/dir
177
-	 *
178
-	 * @param string $path
179
-	 */
180
-	const signal_read = 'read';
181
-
182
-	/**
183
-	 * signal emits when removing file/dir
184
-	 *
185
-	 * @param string $path
186
-	 */
187
-	const signal_delete = 'delete';
188
-
189
-	/**
190
-	 * parameters definitions for signals
191
-	 */
192
-	const signal_param_path = 'path';
193
-	const signal_param_oldpath = 'oldpath';
194
-	const signal_param_newpath = 'newpath';
195
-
196
-	/**
197
-	 * run - changing this flag to false in hook handler will cancel event
198
-	 */
199
-	const signal_param_run = 'run';
200
-
201
-	const signal_create_mount = 'create_mount';
202
-	const signal_delete_mount = 'delete_mount';
203
-	const signal_param_mount_type = 'mounttype';
204
-	const signal_param_users = 'users';
205
-
206
-	/**
207
-	 * @var \OC\Files\Storage\StorageFactory $loader
208
-	 */
209
-	private static $loader;
210
-
211
-	/** @var bool */
212
-	private static $logWarningWhenAddingStorageWrapper = true;
213
-
214
-	/**
215
-	 * @param bool $shouldLog
216
-	 * @return bool previous value
217
-	 * @internal
218
-	 */
219
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
220
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
221
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
222
-		return $previousValue;
223
-	}
224
-
225
-	/**
226
-	 * @param string $wrapperName
227
-	 * @param callable $wrapper
228
-	 * @param int $priority
229
-	 */
230
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
231
-		if (self::$logWarningWhenAddingStorageWrapper) {
232
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
233
-				'wrapper' => $wrapperName,
234
-				'app' => 'filesystem',
235
-			]);
236
-		}
237
-
238
-		$mounts = self::getMountManager()->getAll();
239
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
240
-			// do not re-wrap if storage with this name already existed
241
-			return;
242
-		}
243
-	}
244
-
245
-	/**
246
-	 * Returns the storage factory
247
-	 *
248
-	 * @return \OCP\Files\Storage\IStorageFactory
249
-	 */
250
-	public static function getLoader() {
251
-		if (!self::$loader) {
252
-			self::$loader = new StorageFactory();
253
-		}
254
-		return self::$loader;
255
-	}
256
-
257
-	/**
258
-	 * Returns the mount manager
259
-	 *
260
-	 * @return \OC\Files\Mount\Manager
261
-	 */
262
-	public static function getMountManager($user = '') {
263
-		if (!self::$mounts) {
264
-			\OC_Util::setupFS($user);
265
-		}
266
-		return self::$mounts;
267
-	}
268
-
269
-	/**
270
-	 * get the mountpoint of the storage object for a path
271
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
272
-	 * returned mountpoint is relative to the absolute root of the filesystem
273
-	 * and doesn't take the chroot into account )
274
-	 *
275
-	 * @param string $path
276
-	 * @return string
277
-	 */
278
-	static public function getMountPoint($path) {
279
-		if (!self::$mounts) {
280
-			\OC_Util::setupFS();
281
-		}
282
-		$mount = self::$mounts->find($path);
283
-		if ($mount) {
284
-			return $mount->getMountPoint();
285
-		} else {
286
-			return '';
287
-		}
288
-	}
289
-
290
-	/**
291
-	 * get a list of all mount points in a directory
292
-	 *
293
-	 * @param string $path
294
-	 * @return string[]
295
-	 */
296
-	static public function getMountPoints($path) {
297
-		if (!self::$mounts) {
298
-			\OC_Util::setupFS();
299
-		}
300
-		$result = array();
301
-		$mounts = self::$mounts->findIn($path);
302
-		foreach ($mounts as $mount) {
303
-			$result[] = $mount->getMountPoint();
304
-		}
305
-		return $result;
306
-	}
307
-
308
-	/**
309
-	 * get the storage mounted at $mountPoint
310
-	 *
311
-	 * @param string $mountPoint
312
-	 * @return \OC\Files\Storage\Storage
313
-	 */
314
-	public static function getStorage($mountPoint) {
315
-		if (!self::$mounts) {
316
-			\OC_Util::setupFS();
317
-		}
318
-		$mount = self::$mounts->find($mountPoint);
319
-		return $mount->getStorage();
320
-	}
321
-
322
-	/**
323
-	 * @param string $id
324
-	 * @return Mount\MountPoint[]
325
-	 */
326
-	public static function getMountByStorageId($id) {
327
-		if (!self::$mounts) {
328
-			\OC_Util::setupFS();
329
-		}
330
-		return self::$mounts->findByStorageId($id);
331
-	}
332
-
333
-	/**
334
-	 * @param int $id
335
-	 * @return Mount\MountPoint[]
336
-	 */
337
-	public static function getMountByNumericId($id) {
338
-		if (!self::$mounts) {
339
-			\OC_Util::setupFS();
340
-		}
341
-		return self::$mounts->findByNumericId($id);
342
-	}
343
-
344
-	/**
345
-	 * resolve a path to a storage and internal path
346
-	 *
347
-	 * @param string $path
348
-	 * @return array an array consisting of the storage and the internal path
349
-	 */
350
-	static public function resolvePath($path) {
351
-		if (!self::$mounts) {
352
-			\OC_Util::setupFS();
353
-		}
354
-		$mount = self::$mounts->find($path);
355
-		if ($mount) {
356
-			return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/'));
357
-		} else {
358
-			return array(null, null);
359
-		}
360
-	}
361
-
362
-	static public function init($user, $root) {
363
-		if (self::$defaultInstance) {
364
-			return false;
365
-		}
366
-		self::getLoader();
367
-		self::$defaultInstance = new View($root);
368
-
369
-		if (!self::$mounts) {
370
-			self::$mounts = \OC::$server->getMountManager();
371
-		}
372
-
373
-		//load custom mount config
374
-		self::initMountPoints($user);
375
-
376
-		self::$loaded = true;
377
-
378
-		return true;
379
-	}
380
-
381
-	static public function initMountManager() {
382
-		if (!self::$mounts) {
383
-			self::$mounts = \OC::$server->getMountManager();
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * Initialize system and personal mount points for a user
389
-	 *
390
-	 * @param string $user
391
-	 * @throws \OC\User\NoUserException if the user is not available
392
-	 */
393
-	public static function initMountPoints($user = '') {
394
-		if ($user == '') {
395
-			$user = \OC_User::getUser();
396
-		}
397
-		if ($user === null || $user === false || $user === '') {
398
-			throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
399
-		}
400
-		if (isset(self::$usersSetup[$user])) {
401
-			return;
402
-		}
403
-
404
-		$userManager = \OC::$server->getUserManager();
405
-		$userObject = $userManager->get($user);
406
-
407
-		if (is_null($userObject)) {
408
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
409
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
410
-		}
411
-
412
-		self::$usersSetup[$user] = true;
413
-
414
-		/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
415
-		$mountConfigManager = \OC::$server->getMountProviderCollection();
416
-
417
-		// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
418
-		$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
419
-
420
-		self::getMountManager()->addMount($homeMount);
421
-
422
-		\OC\Files\Filesystem::getStorage($user);
423
-
424
-		// Chance to mount for other storages
425
-		if ($userObject) {
426
-			$mounts = $mountConfigManager->getMountsForUser($userObject);
427
-			array_walk($mounts, array(self::$mounts, 'addMount'));
428
-			$mounts[] = $homeMount;
429
-			$mountConfigManager->registerMounts($userObject, $mounts);
430
-		}
431
-
432
-		self::listenForNewMountProviders($mountConfigManager, $userManager);
433
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user));
434
-	}
435
-
436
-	/**
437
-	 * Get mounts from mount providers that are registered after setup
438
-	 *
439
-	 * @param MountProviderCollection $mountConfigManager
440
-	 * @param IUserManager $userManager
441
-	 */
442
-	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
443
-		if (!self::$listeningForProviders) {
444
-			self::$listeningForProviders = true;
445
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
446
-				foreach (Filesystem::$usersSetup as $user => $setup) {
447
-					$userObject = $userManager->get($user);
448
-					if ($userObject) {
449
-						$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
450
-						array_walk($mounts, array(self::$mounts, 'addMount'));
451
-					}
452
-				}
453
-			});
454
-		}
455
-	}
456
-
457
-	/**
458
-	 * get the default filesystem view
459
-	 *
460
-	 * @return View
461
-	 */
462
-	static public function getView() {
463
-		return self::$defaultInstance;
464
-	}
465
-
466
-	/**
467
-	 * tear down the filesystem, removing all storage providers
468
-	 */
469
-	static public function tearDown() {
470
-		self::clearMounts();
471
-		self::$defaultInstance = null;
472
-	}
473
-
474
-	/**
475
-	 * get the relative path of the root data directory for the current user
476
-	 *
477
-	 * @return string
478
-	 *
479
-	 * Returns path like /admin/files
480
-	 */
481
-	static public function getRoot() {
482
-		if (!self::$defaultInstance) {
483
-			return null;
484
-		}
485
-		return self::$defaultInstance->getRoot();
486
-	}
487
-
488
-	/**
489
-	 * clear all mounts and storage backends
490
-	 */
491
-	public static function clearMounts() {
492
-		if (self::$mounts) {
493
-			self::$usersSetup = array();
494
-			self::$mounts->clear();
495
-		}
496
-	}
497
-
498
-	/**
499
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
500
-	 *
501
-	 * @param \OC\Files\Storage\Storage|string $class
502
-	 * @param array $arguments
503
-	 * @param string $mountpoint
504
-	 */
505
-	static public function mount($class, $arguments, $mountpoint) {
506
-		if (!self::$mounts) {
507
-			\OC_Util::setupFS();
508
-		}
509
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
510
-		self::$mounts->addMount($mount);
511
-	}
512
-
513
-	/**
514
-	 * return the path to a local version of the file
515
-	 * we need this because we can't know if a file is stored local or not from
516
-	 * outside the filestorage and for some purposes a local file is needed
517
-	 *
518
-	 * @param string $path
519
-	 * @return string
520
-	 */
521
-	static public function getLocalFile($path) {
522
-		return self::$defaultInstance->getLocalFile($path);
523
-	}
524
-
525
-	/**
526
-	 * @param string $path
527
-	 * @return string
528
-	 */
529
-	static public function getLocalFolder($path) {
530
-		return self::$defaultInstance->getLocalFolder($path);
531
-	}
532
-
533
-	/**
534
-	 * return path to file which reflects one visible in browser
535
-	 *
536
-	 * @param string $path
537
-	 * @return string
538
-	 */
539
-	static public function getLocalPath($path) {
540
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
541
-		$newpath = $path;
542
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
543
-			$newpath = substr($path, strlen($datadir));
544
-		}
545
-		return $newpath;
546
-	}
547
-
548
-	/**
549
-	 * check if the requested path is valid
550
-	 *
551
-	 * @param string $path
552
-	 * @return bool
553
-	 */
554
-	static public function isValidPath($path) {
555
-		$path = self::normalizePath($path);
556
-		if (!$path || $path[0] !== '/') {
557
-			$path = '/' . $path;
558
-		}
559
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
560
-			return false;
561
-		}
562
-		return true;
563
-	}
564
-
565
-	/**
566
-	 * checks if a file is blacklisted for storage in the filesystem
567
-	 * Listens to write and rename hooks
568
-	 *
569
-	 * @param array $data from hook
570
-	 */
571
-	static public function isBlacklisted($data) {
572
-		if (isset($data['path'])) {
573
-			$path = $data['path'];
574
-		} else if (isset($data['newpath'])) {
575
-			$path = $data['newpath'];
576
-		}
577
-		if (isset($path)) {
578
-			if (self::isFileBlacklisted($path)) {
579
-				$data['run'] = false;
580
-			}
581
-		}
582
-	}
583
-
584
-	/**
585
-	 * @param string $filename
586
-	 * @return bool
587
-	 */
588
-	static public function isFileBlacklisted($filename) {
589
-		$filename = self::normalizePath($filename);
590
-
591
-		$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess'));
592
-		$filename = strtolower(basename($filename));
593
-		return in_array($filename, $blacklist);
594
-	}
595
-
596
-	/**
597
-	 * check if the directory should be ignored when scanning
598
-	 * NOTE: the special directories . and .. would cause never ending recursion
599
-	 *
600
-	 * @param String $dir
601
-	 * @return boolean
602
-	 */
603
-	static public function isIgnoredDir($dir) {
604
-		if ($dir === '.' || $dir === '..') {
605
-			return true;
606
-		}
607
-		return false;
608
-	}
609
-
610
-	/**
611
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
612
-	 */
613
-	static public function mkdir($path) {
614
-		return self::$defaultInstance->mkdir($path);
615
-	}
616
-
617
-	static public function rmdir($path) {
618
-		return self::$defaultInstance->rmdir($path);
619
-	}
620
-
621
-	static public function opendir($path) {
622
-		return self::$defaultInstance->opendir($path);
623
-	}
624
-
625
-	static public function readdir($path) {
626
-		return self::$defaultInstance->readdir($path);
627
-	}
628
-
629
-	static public function is_dir($path) {
630
-		return self::$defaultInstance->is_dir($path);
631
-	}
632
-
633
-	static public function is_file($path) {
634
-		return self::$defaultInstance->is_file($path);
635
-	}
636
-
637
-	static public function stat($path) {
638
-		return self::$defaultInstance->stat($path);
639
-	}
640
-
641
-	static public function filetype($path) {
642
-		return self::$defaultInstance->filetype($path);
643
-	}
644
-
645
-	static public function filesize($path) {
646
-		return self::$defaultInstance->filesize($path);
647
-	}
648
-
649
-	static public function readfile($path) {
650
-		return self::$defaultInstance->readfile($path);
651
-	}
652
-
653
-	static public function isCreatable($path) {
654
-		return self::$defaultInstance->isCreatable($path);
655
-	}
656
-
657
-	static public function isReadable($path) {
658
-		return self::$defaultInstance->isReadable($path);
659
-	}
660
-
661
-	static public function isUpdatable($path) {
662
-		return self::$defaultInstance->isUpdatable($path);
663
-	}
664
-
665
-	static public function isDeletable($path) {
666
-		return self::$defaultInstance->isDeletable($path);
667
-	}
668
-
669
-	static public function isSharable($path) {
670
-		return self::$defaultInstance->isSharable($path);
671
-	}
672
-
673
-	static public function file_exists($path) {
674
-		return self::$defaultInstance->file_exists($path);
675
-	}
676
-
677
-	static public function filemtime($path) {
678
-		return self::$defaultInstance->filemtime($path);
679
-	}
680
-
681
-	static public function touch($path, $mtime = null) {
682
-		return self::$defaultInstance->touch($path, $mtime);
683
-	}
684
-
685
-	/**
686
-	 * @return string
687
-	 */
688
-	static public function file_get_contents($path) {
689
-		return self::$defaultInstance->file_get_contents($path);
690
-	}
691
-
692
-	static public function file_put_contents($path, $data) {
693
-		return self::$defaultInstance->file_put_contents($path, $data);
694
-	}
695
-
696
-	static public function unlink($path) {
697
-		return self::$defaultInstance->unlink($path);
698
-	}
699
-
700
-	static public function rename($path1, $path2) {
701
-		return self::$defaultInstance->rename($path1, $path2);
702
-	}
703
-
704
-	static public function copy($path1, $path2) {
705
-		return self::$defaultInstance->copy($path1, $path2);
706
-	}
707
-
708
-	static public function fopen($path, $mode) {
709
-		return self::$defaultInstance->fopen($path, $mode);
710
-	}
711
-
712
-	/**
713
-	 * @return string
714
-	 */
715
-	static public function toTmpFile($path) {
716
-		return self::$defaultInstance->toTmpFile($path);
717
-	}
718
-
719
-	static public function fromTmpFile($tmpFile, $path) {
720
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
721
-	}
722
-
723
-	static public function getMimeType($path) {
724
-		return self::$defaultInstance->getMimeType($path);
725
-	}
726
-
727
-	static public function hash($type, $path, $raw = false) {
728
-		return self::$defaultInstance->hash($type, $path, $raw);
729
-	}
730
-
731
-	static public function free_space($path = '/') {
732
-		return self::$defaultInstance->free_space($path);
733
-	}
734
-
735
-	static public function search($query) {
736
-		return self::$defaultInstance->search($query);
737
-	}
738
-
739
-	/**
740
-	 * @param string $query
741
-	 */
742
-	static public function searchByMime($query) {
743
-		return self::$defaultInstance->searchByMime($query);
744
-	}
745
-
746
-	/**
747
-	 * @param string|int $tag name or tag id
748
-	 * @param string $userId owner of the tags
749
-	 * @return FileInfo[] array or file info
750
-	 */
751
-	static public function searchByTag($tag, $userId) {
752
-		return self::$defaultInstance->searchByTag($tag, $userId);
753
-	}
754
-
755
-	/**
756
-	 * check if a file or folder has been updated since $time
757
-	 *
758
-	 * @param string $path
759
-	 * @param int $time
760
-	 * @return bool
761
-	 */
762
-	static public function hasUpdated($path, $time) {
763
-		return self::$defaultInstance->hasUpdated($path, $time);
764
-	}
765
-
766
-	/**
767
-	 * Fix common problems with a file path
768
-	 *
769
-	 * @param string $path
770
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
771
-	 * @param bool $isAbsolutePath whether the given path is absolute
772
-	 * @param bool $keepUnicode true to disable unicode normalization
773
-	 * @return string
774
-	 */
775
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
776
-		if (is_null(self::$normalizedPathCache)) {
777
-			self::$normalizedPathCache = new CappedMemoryCache();
778
-		}
779
-
780
-		/**
781
-		 * FIXME: This is a workaround for existing classes and files which call
782
-		 *        this function with another type than a valid string. This
783
-		 *        conversion should get removed as soon as all existing
784
-		 *        function calls have been fixed.
785
-		 */
786
-		$path = (string)$path;
787
-
788
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
789
-
790
-		if (isset(self::$normalizedPathCache[$cacheKey])) {
791
-			return self::$normalizedPathCache[$cacheKey];
792
-		}
793
-
794
-		if ($path == '') {
795
-			return '/';
796
-		}
797
-
798
-		//normalize unicode if possible
799
-		if (!$keepUnicode) {
800
-			$path = \OC_Util::normalizeUnicode($path);
801
-		}
802
-
803
-		//no windows style slashes
804
-		$path = str_replace('\\', '/', $path);
805
-
806
-		//add leading slash
807
-		if ($path[0] !== '/') {
808
-			$path = '/' . $path;
809
-		}
810
-
811
-		// remove '/./'
812
-		// ugly, but str_replace() can't replace them all in one go
813
-		// as the replacement itself is part of the search string
814
-		// which will only be found during the next iteration
815
-		while (strpos($path, '/./') !== false) {
816
-			$path = str_replace('/./', '/', $path);
817
-		}
818
-		// remove sequences of slashes
819
-		$path = preg_replace('#/{2,}#', '/', $path);
820
-
821
-		//remove trailing slash
822
-		if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') {
823
-			$path = substr($path, 0, -1);
824
-		}
825
-
826
-		// remove trailing '/.'
827
-		if (substr($path, -2) == '/.') {
828
-			$path = substr($path, 0, -2);
829
-		}
830
-
831
-		$normalizedPath = $path;
832
-		self::$normalizedPathCache[$cacheKey] = $normalizedPath;
833
-
834
-		return $normalizedPath;
835
-	}
836
-
837
-	/**
838
-	 * get the filesystem info
839
-	 *
840
-	 * @param string $path
841
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
842
-	 * defaults to true
843
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
844
-	 */
845
-	public static function getFileInfo($path, $includeMountPoints = true) {
846
-		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
847
-	}
848
-
849
-	/**
850
-	 * change file metadata
851
-	 *
852
-	 * @param string $path
853
-	 * @param array $data
854
-	 * @return int
855
-	 *
856
-	 * returns the fileid of the updated file
857
-	 */
858
-	public static function putFileInfo($path, $data) {
859
-		return self::$defaultInstance->putFileInfo($path, $data);
860
-	}
861
-
862
-	/**
863
-	 * get the content of a directory
864
-	 *
865
-	 * @param string $directory path under datadirectory
866
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
867
-	 * @return \OC\Files\FileInfo[]
868
-	 */
869
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
870
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
871
-	}
872
-
873
-	/**
874
-	 * Get the path of a file by id
875
-	 *
876
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
877
-	 *
878
-	 * @param int $id
879
-	 * @throws NotFoundException
880
-	 * @return string
881
-	 */
882
-	public static function getPath($id) {
883
-		return self::$defaultInstance->getPath($id);
884
-	}
885
-
886
-	/**
887
-	 * Get the owner for a file or folder
888
-	 *
889
-	 * @param string $path
890
-	 * @return string
891
-	 */
892
-	public static function getOwner($path) {
893
-		return self::$defaultInstance->getOwner($path);
894
-	}
895
-
896
-	/**
897
-	 * get the ETag for a file or folder
898
-	 *
899
-	 * @param string $path
900
-	 * @return string
901
-	 */
902
-	static public function getETag($path) {
903
-		return self::$defaultInstance->getETag($path);
904
-	}
72
+    /**
73
+     * @var Mount\Manager $mounts
74
+     */
75
+    private static $mounts;
76
+
77
+    public static $loaded = false;
78
+    /**
79
+     * @var \OC\Files\View $defaultInstance
80
+     */
81
+    static private $defaultInstance;
82
+
83
+    static private $usersSetup = array();
84
+
85
+    static private $normalizedPathCache = null;
86
+
87
+    static private $listeningForProviders = false;
88
+
89
+    /**
90
+     * classname which used for hooks handling
91
+     * used as signalclass in OC_Hooks::emit()
92
+     */
93
+    const CLASSNAME = 'OC_Filesystem';
94
+
95
+    /**
96
+     * signalname emitted before file renaming
97
+     *
98
+     * @param string $oldpath
99
+     * @param string $newpath
100
+     */
101
+    const signal_rename = 'rename';
102
+
103
+    /**
104
+     * signal emitted after file renaming
105
+     *
106
+     * @param string $oldpath
107
+     * @param string $newpath
108
+     */
109
+    const signal_post_rename = 'post_rename';
110
+
111
+    /**
112
+     * signal emitted before file/dir creation
113
+     *
114
+     * @param string $path
115
+     * @param bool $run changing this flag to false in hook handler will cancel event
116
+     */
117
+    const signal_create = 'create';
118
+
119
+    /**
120
+     * signal emitted after file/dir creation
121
+     *
122
+     * @param string $path
123
+     * @param bool $run changing this flag to false in hook handler will cancel event
124
+     */
125
+    const signal_post_create = 'post_create';
126
+
127
+    /**
128
+     * signal emits before file/dir copy
129
+     *
130
+     * @param string $oldpath
131
+     * @param string $newpath
132
+     * @param bool $run changing this flag to false in hook handler will cancel event
133
+     */
134
+    const signal_copy = 'copy';
135
+
136
+    /**
137
+     * signal emits after file/dir copy
138
+     *
139
+     * @param string $oldpath
140
+     * @param string $newpath
141
+     */
142
+    const signal_post_copy = 'post_copy';
143
+
144
+    /**
145
+     * signal emits before file/dir save
146
+     *
147
+     * @param string $path
148
+     * @param bool $run changing this flag to false in hook handler will cancel event
149
+     */
150
+    const signal_write = 'write';
151
+
152
+    /**
153
+     * signal emits after file/dir save
154
+     *
155
+     * @param string $path
156
+     */
157
+    const signal_post_write = 'post_write';
158
+
159
+    /**
160
+     * signal emitted before file/dir update
161
+     *
162
+     * @param string $path
163
+     * @param bool $run changing this flag to false in hook handler will cancel event
164
+     */
165
+    const signal_update = 'update';
166
+
167
+    /**
168
+     * signal emitted after file/dir update
169
+     *
170
+     * @param string $path
171
+     * @param bool $run changing this flag to false in hook handler will cancel event
172
+     */
173
+    const signal_post_update = 'post_update';
174
+
175
+    /**
176
+     * signal emits when reading file/dir
177
+     *
178
+     * @param string $path
179
+     */
180
+    const signal_read = 'read';
181
+
182
+    /**
183
+     * signal emits when removing file/dir
184
+     *
185
+     * @param string $path
186
+     */
187
+    const signal_delete = 'delete';
188
+
189
+    /**
190
+     * parameters definitions for signals
191
+     */
192
+    const signal_param_path = 'path';
193
+    const signal_param_oldpath = 'oldpath';
194
+    const signal_param_newpath = 'newpath';
195
+
196
+    /**
197
+     * run - changing this flag to false in hook handler will cancel event
198
+     */
199
+    const signal_param_run = 'run';
200
+
201
+    const signal_create_mount = 'create_mount';
202
+    const signal_delete_mount = 'delete_mount';
203
+    const signal_param_mount_type = 'mounttype';
204
+    const signal_param_users = 'users';
205
+
206
+    /**
207
+     * @var \OC\Files\Storage\StorageFactory $loader
208
+     */
209
+    private static $loader;
210
+
211
+    /** @var bool */
212
+    private static $logWarningWhenAddingStorageWrapper = true;
213
+
214
+    /**
215
+     * @param bool $shouldLog
216
+     * @return bool previous value
217
+     * @internal
218
+     */
219
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
220
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
221
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
222
+        return $previousValue;
223
+    }
224
+
225
+    /**
226
+     * @param string $wrapperName
227
+     * @param callable $wrapper
228
+     * @param int $priority
229
+     */
230
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
231
+        if (self::$logWarningWhenAddingStorageWrapper) {
232
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
233
+                'wrapper' => $wrapperName,
234
+                'app' => 'filesystem',
235
+            ]);
236
+        }
237
+
238
+        $mounts = self::getMountManager()->getAll();
239
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
240
+            // do not re-wrap if storage with this name already existed
241
+            return;
242
+        }
243
+    }
244
+
245
+    /**
246
+     * Returns the storage factory
247
+     *
248
+     * @return \OCP\Files\Storage\IStorageFactory
249
+     */
250
+    public static function getLoader() {
251
+        if (!self::$loader) {
252
+            self::$loader = new StorageFactory();
253
+        }
254
+        return self::$loader;
255
+    }
256
+
257
+    /**
258
+     * Returns the mount manager
259
+     *
260
+     * @return \OC\Files\Mount\Manager
261
+     */
262
+    public static function getMountManager($user = '') {
263
+        if (!self::$mounts) {
264
+            \OC_Util::setupFS($user);
265
+        }
266
+        return self::$mounts;
267
+    }
268
+
269
+    /**
270
+     * get the mountpoint of the storage object for a path
271
+     * ( note: because a storage is not always mounted inside the fakeroot, the
272
+     * returned mountpoint is relative to the absolute root of the filesystem
273
+     * and doesn't take the chroot into account )
274
+     *
275
+     * @param string $path
276
+     * @return string
277
+     */
278
+    static public function getMountPoint($path) {
279
+        if (!self::$mounts) {
280
+            \OC_Util::setupFS();
281
+        }
282
+        $mount = self::$mounts->find($path);
283
+        if ($mount) {
284
+            return $mount->getMountPoint();
285
+        } else {
286
+            return '';
287
+        }
288
+    }
289
+
290
+    /**
291
+     * get a list of all mount points in a directory
292
+     *
293
+     * @param string $path
294
+     * @return string[]
295
+     */
296
+    static public function getMountPoints($path) {
297
+        if (!self::$mounts) {
298
+            \OC_Util::setupFS();
299
+        }
300
+        $result = array();
301
+        $mounts = self::$mounts->findIn($path);
302
+        foreach ($mounts as $mount) {
303
+            $result[] = $mount->getMountPoint();
304
+        }
305
+        return $result;
306
+    }
307
+
308
+    /**
309
+     * get the storage mounted at $mountPoint
310
+     *
311
+     * @param string $mountPoint
312
+     * @return \OC\Files\Storage\Storage
313
+     */
314
+    public static function getStorage($mountPoint) {
315
+        if (!self::$mounts) {
316
+            \OC_Util::setupFS();
317
+        }
318
+        $mount = self::$mounts->find($mountPoint);
319
+        return $mount->getStorage();
320
+    }
321
+
322
+    /**
323
+     * @param string $id
324
+     * @return Mount\MountPoint[]
325
+     */
326
+    public static function getMountByStorageId($id) {
327
+        if (!self::$mounts) {
328
+            \OC_Util::setupFS();
329
+        }
330
+        return self::$mounts->findByStorageId($id);
331
+    }
332
+
333
+    /**
334
+     * @param int $id
335
+     * @return Mount\MountPoint[]
336
+     */
337
+    public static function getMountByNumericId($id) {
338
+        if (!self::$mounts) {
339
+            \OC_Util::setupFS();
340
+        }
341
+        return self::$mounts->findByNumericId($id);
342
+    }
343
+
344
+    /**
345
+     * resolve a path to a storage and internal path
346
+     *
347
+     * @param string $path
348
+     * @return array an array consisting of the storage and the internal path
349
+     */
350
+    static public function resolvePath($path) {
351
+        if (!self::$mounts) {
352
+            \OC_Util::setupFS();
353
+        }
354
+        $mount = self::$mounts->find($path);
355
+        if ($mount) {
356
+            return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/'));
357
+        } else {
358
+            return array(null, null);
359
+        }
360
+    }
361
+
362
+    static public function init($user, $root) {
363
+        if (self::$defaultInstance) {
364
+            return false;
365
+        }
366
+        self::getLoader();
367
+        self::$defaultInstance = new View($root);
368
+
369
+        if (!self::$mounts) {
370
+            self::$mounts = \OC::$server->getMountManager();
371
+        }
372
+
373
+        //load custom mount config
374
+        self::initMountPoints($user);
375
+
376
+        self::$loaded = true;
377
+
378
+        return true;
379
+    }
380
+
381
+    static public function initMountManager() {
382
+        if (!self::$mounts) {
383
+            self::$mounts = \OC::$server->getMountManager();
384
+        }
385
+    }
386
+
387
+    /**
388
+     * Initialize system and personal mount points for a user
389
+     *
390
+     * @param string $user
391
+     * @throws \OC\User\NoUserException if the user is not available
392
+     */
393
+    public static function initMountPoints($user = '') {
394
+        if ($user == '') {
395
+            $user = \OC_User::getUser();
396
+        }
397
+        if ($user === null || $user === false || $user === '') {
398
+            throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
399
+        }
400
+        if (isset(self::$usersSetup[$user])) {
401
+            return;
402
+        }
403
+
404
+        $userManager = \OC::$server->getUserManager();
405
+        $userObject = $userManager->get($user);
406
+
407
+        if (is_null($userObject)) {
408
+            \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
409
+            throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
410
+        }
411
+
412
+        self::$usersSetup[$user] = true;
413
+
414
+        /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
415
+        $mountConfigManager = \OC::$server->getMountProviderCollection();
416
+
417
+        // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
418
+        $homeMount = $mountConfigManager->getHomeMountForUser($userObject);
419
+
420
+        self::getMountManager()->addMount($homeMount);
421
+
422
+        \OC\Files\Filesystem::getStorage($user);
423
+
424
+        // Chance to mount for other storages
425
+        if ($userObject) {
426
+            $mounts = $mountConfigManager->getMountsForUser($userObject);
427
+            array_walk($mounts, array(self::$mounts, 'addMount'));
428
+            $mounts[] = $homeMount;
429
+            $mountConfigManager->registerMounts($userObject, $mounts);
430
+        }
431
+
432
+        self::listenForNewMountProviders($mountConfigManager, $userManager);
433
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user));
434
+    }
435
+
436
+    /**
437
+     * Get mounts from mount providers that are registered after setup
438
+     *
439
+     * @param MountProviderCollection $mountConfigManager
440
+     * @param IUserManager $userManager
441
+     */
442
+    private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
443
+        if (!self::$listeningForProviders) {
444
+            self::$listeningForProviders = true;
445
+            $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
446
+                foreach (Filesystem::$usersSetup as $user => $setup) {
447
+                    $userObject = $userManager->get($user);
448
+                    if ($userObject) {
449
+                        $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
450
+                        array_walk($mounts, array(self::$mounts, 'addMount'));
451
+                    }
452
+                }
453
+            });
454
+        }
455
+    }
456
+
457
+    /**
458
+     * get the default filesystem view
459
+     *
460
+     * @return View
461
+     */
462
+    static public function getView() {
463
+        return self::$defaultInstance;
464
+    }
465
+
466
+    /**
467
+     * tear down the filesystem, removing all storage providers
468
+     */
469
+    static public function tearDown() {
470
+        self::clearMounts();
471
+        self::$defaultInstance = null;
472
+    }
473
+
474
+    /**
475
+     * get the relative path of the root data directory for the current user
476
+     *
477
+     * @return string
478
+     *
479
+     * Returns path like /admin/files
480
+     */
481
+    static public function getRoot() {
482
+        if (!self::$defaultInstance) {
483
+            return null;
484
+        }
485
+        return self::$defaultInstance->getRoot();
486
+    }
487
+
488
+    /**
489
+     * clear all mounts and storage backends
490
+     */
491
+    public static function clearMounts() {
492
+        if (self::$mounts) {
493
+            self::$usersSetup = array();
494
+            self::$mounts->clear();
495
+        }
496
+    }
497
+
498
+    /**
499
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
500
+     *
501
+     * @param \OC\Files\Storage\Storage|string $class
502
+     * @param array $arguments
503
+     * @param string $mountpoint
504
+     */
505
+    static public function mount($class, $arguments, $mountpoint) {
506
+        if (!self::$mounts) {
507
+            \OC_Util::setupFS();
508
+        }
509
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
510
+        self::$mounts->addMount($mount);
511
+    }
512
+
513
+    /**
514
+     * return the path to a local version of the file
515
+     * we need this because we can't know if a file is stored local or not from
516
+     * outside the filestorage and for some purposes a local file is needed
517
+     *
518
+     * @param string $path
519
+     * @return string
520
+     */
521
+    static public function getLocalFile($path) {
522
+        return self::$defaultInstance->getLocalFile($path);
523
+    }
524
+
525
+    /**
526
+     * @param string $path
527
+     * @return string
528
+     */
529
+    static public function getLocalFolder($path) {
530
+        return self::$defaultInstance->getLocalFolder($path);
531
+    }
532
+
533
+    /**
534
+     * return path to file which reflects one visible in browser
535
+     *
536
+     * @param string $path
537
+     * @return string
538
+     */
539
+    static public function getLocalPath($path) {
540
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
541
+        $newpath = $path;
542
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
543
+            $newpath = substr($path, strlen($datadir));
544
+        }
545
+        return $newpath;
546
+    }
547
+
548
+    /**
549
+     * check if the requested path is valid
550
+     *
551
+     * @param string $path
552
+     * @return bool
553
+     */
554
+    static public function isValidPath($path) {
555
+        $path = self::normalizePath($path);
556
+        if (!$path || $path[0] !== '/') {
557
+            $path = '/' . $path;
558
+        }
559
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
560
+            return false;
561
+        }
562
+        return true;
563
+    }
564
+
565
+    /**
566
+     * checks if a file is blacklisted for storage in the filesystem
567
+     * Listens to write and rename hooks
568
+     *
569
+     * @param array $data from hook
570
+     */
571
+    static public function isBlacklisted($data) {
572
+        if (isset($data['path'])) {
573
+            $path = $data['path'];
574
+        } else if (isset($data['newpath'])) {
575
+            $path = $data['newpath'];
576
+        }
577
+        if (isset($path)) {
578
+            if (self::isFileBlacklisted($path)) {
579
+                $data['run'] = false;
580
+            }
581
+        }
582
+    }
583
+
584
+    /**
585
+     * @param string $filename
586
+     * @return bool
587
+     */
588
+    static public function isFileBlacklisted($filename) {
589
+        $filename = self::normalizePath($filename);
590
+
591
+        $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess'));
592
+        $filename = strtolower(basename($filename));
593
+        return in_array($filename, $blacklist);
594
+    }
595
+
596
+    /**
597
+     * check if the directory should be ignored when scanning
598
+     * NOTE: the special directories . and .. would cause never ending recursion
599
+     *
600
+     * @param String $dir
601
+     * @return boolean
602
+     */
603
+    static public function isIgnoredDir($dir) {
604
+        if ($dir === '.' || $dir === '..') {
605
+            return true;
606
+        }
607
+        return false;
608
+    }
609
+
610
+    /**
611
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
612
+     */
613
+    static public function mkdir($path) {
614
+        return self::$defaultInstance->mkdir($path);
615
+    }
616
+
617
+    static public function rmdir($path) {
618
+        return self::$defaultInstance->rmdir($path);
619
+    }
620
+
621
+    static public function opendir($path) {
622
+        return self::$defaultInstance->opendir($path);
623
+    }
624
+
625
+    static public function readdir($path) {
626
+        return self::$defaultInstance->readdir($path);
627
+    }
628
+
629
+    static public function is_dir($path) {
630
+        return self::$defaultInstance->is_dir($path);
631
+    }
632
+
633
+    static public function is_file($path) {
634
+        return self::$defaultInstance->is_file($path);
635
+    }
636
+
637
+    static public function stat($path) {
638
+        return self::$defaultInstance->stat($path);
639
+    }
640
+
641
+    static public function filetype($path) {
642
+        return self::$defaultInstance->filetype($path);
643
+    }
644
+
645
+    static public function filesize($path) {
646
+        return self::$defaultInstance->filesize($path);
647
+    }
648
+
649
+    static public function readfile($path) {
650
+        return self::$defaultInstance->readfile($path);
651
+    }
652
+
653
+    static public function isCreatable($path) {
654
+        return self::$defaultInstance->isCreatable($path);
655
+    }
656
+
657
+    static public function isReadable($path) {
658
+        return self::$defaultInstance->isReadable($path);
659
+    }
660
+
661
+    static public function isUpdatable($path) {
662
+        return self::$defaultInstance->isUpdatable($path);
663
+    }
664
+
665
+    static public function isDeletable($path) {
666
+        return self::$defaultInstance->isDeletable($path);
667
+    }
668
+
669
+    static public function isSharable($path) {
670
+        return self::$defaultInstance->isSharable($path);
671
+    }
672
+
673
+    static public function file_exists($path) {
674
+        return self::$defaultInstance->file_exists($path);
675
+    }
676
+
677
+    static public function filemtime($path) {
678
+        return self::$defaultInstance->filemtime($path);
679
+    }
680
+
681
+    static public function touch($path, $mtime = null) {
682
+        return self::$defaultInstance->touch($path, $mtime);
683
+    }
684
+
685
+    /**
686
+     * @return string
687
+     */
688
+    static public function file_get_contents($path) {
689
+        return self::$defaultInstance->file_get_contents($path);
690
+    }
691
+
692
+    static public function file_put_contents($path, $data) {
693
+        return self::$defaultInstance->file_put_contents($path, $data);
694
+    }
695
+
696
+    static public function unlink($path) {
697
+        return self::$defaultInstance->unlink($path);
698
+    }
699
+
700
+    static public function rename($path1, $path2) {
701
+        return self::$defaultInstance->rename($path1, $path2);
702
+    }
703
+
704
+    static public function copy($path1, $path2) {
705
+        return self::$defaultInstance->copy($path1, $path2);
706
+    }
707
+
708
+    static public function fopen($path, $mode) {
709
+        return self::$defaultInstance->fopen($path, $mode);
710
+    }
711
+
712
+    /**
713
+     * @return string
714
+     */
715
+    static public function toTmpFile($path) {
716
+        return self::$defaultInstance->toTmpFile($path);
717
+    }
718
+
719
+    static public function fromTmpFile($tmpFile, $path) {
720
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
721
+    }
722
+
723
+    static public function getMimeType($path) {
724
+        return self::$defaultInstance->getMimeType($path);
725
+    }
726
+
727
+    static public function hash($type, $path, $raw = false) {
728
+        return self::$defaultInstance->hash($type, $path, $raw);
729
+    }
730
+
731
+    static public function free_space($path = '/') {
732
+        return self::$defaultInstance->free_space($path);
733
+    }
734
+
735
+    static public function search($query) {
736
+        return self::$defaultInstance->search($query);
737
+    }
738
+
739
+    /**
740
+     * @param string $query
741
+     */
742
+    static public function searchByMime($query) {
743
+        return self::$defaultInstance->searchByMime($query);
744
+    }
745
+
746
+    /**
747
+     * @param string|int $tag name or tag id
748
+     * @param string $userId owner of the tags
749
+     * @return FileInfo[] array or file info
750
+     */
751
+    static public function searchByTag($tag, $userId) {
752
+        return self::$defaultInstance->searchByTag($tag, $userId);
753
+    }
754
+
755
+    /**
756
+     * check if a file or folder has been updated since $time
757
+     *
758
+     * @param string $path
759
+     * @param int $time
760
+     * @return bool
761
+     */
762
+    static public function hasUpdated($path, $time) {
763
+        return self::$defaultInstance->hasUpdated($path, $time);
764
+    }
765
+
766
+    /**
767
+     * Fix common problems with a file path
768
+     *
769
+     * @param string $path
770
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
771
+     * @param bool $isAbsolutePath whether the given path is absolute
772
+     * @param bool $keepUnicode true to disable unicode normalization
773
+     * @return string
774
+     */
775
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
776
+        if (is_null(self::$normalizedPathCache)) {
777
+            self::$normalizedPathCache = new CappedMemoryCache();
778
+        }
779
+
780
+        /**
781
+         * FIXME: This is a workaround for existing classes and files which call
782
+         *        this function with another type than a valid string. This
783
+         *        conversion should get removed as soon as all existing
784
+         *        function calls have been fixed.
785
+         */
786
+        $path = (string)$path;
787
+
788
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
789
+
790
+        if (isset(self::$normalizedPathCache[$cacheKey])) {
791
+            return self::$normalizedPathCache[$cacheKey];
792
+        }
793
+
794
+        if ($path == '') {
795
+            return '/';
796
+        }
797
+
798
+        //normalize unicode if possible
799
+        if (!$keepUnicode) {
800
+            $path = \OC_Util::normalizeUnicode($path);
801
+        }
802
+
803
+        //no windows style slashes
804
+        $path = str_replace('\\', '/', $path);
805
+
806
+        //add leading slash
807
+        if ($path[0] !== '/') {
808
+            $path = '/' . $path;
809
+        }
810
+
811
+        // remove '/./'
812
+        // ugly, but str_replace() can't replace them all in one go
813
+        // as the replacement itself is part of the search string
814
+        // which will only be found during the next iteration
815
+        while (strpos($path, '/./') !== false) {
816
+            $path = str_replace('/./', '/', $path);
817
+        }
818
+        // remove sequences of slashes
819
+        $path = preg_replace('#/{2,}#', '/', $path);
820
+
821
+        //remove trailing slash
822
+        if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') {
823
+            $path = substr($path, 0, -1);
824
+        }
825
+
826
+        // remove trailing '/.'
827
+        if (substr($path, -2) == '/.') {
828
+            $path = substr($path, 0, -2);
829
+        }
830
+
831
+        $normalizedPath = $path;
832
+        self::$normalizedPathCache[$cacheKey] = $normalizedPath;
833
+
834
+        return $normalizedPath;
835
+    }
836
+
837
+    /**
838
+     * get the filesystem info
839
+     *
840
+     * @param string $path
841
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
842
+     * defaults to true
843
+     * @return \OC\Files\FileInfo|bool False if file does not exist
844
+     */
845
+    public static function getFileInfo($path, $includeMountPoints = true) {
846
+        return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
847
+    }
848
+
849
+    /**
850
+     * change file metadata
851
+     *
852
+     * @param string $path
853
+     * @param array $data
854
+     * @return int
855
+     *
856
+     * returns the fileid of the updated file
857
+     */
858
+    public static function putFileInfo($path, $data) {
859
+        return self::$defaultInstance->putFileInfo($path, $data);
860
+    }
861
+
862
+    /**
863
+     * get the content of a directory
864
+     *
865
+     * @param string $directory path under datadirectory
866
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
867
+     * @return \OC\Files\FileInfo[]
868
+     */
869
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
870
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
871
+    }
872
+
873
+    /**
874
+     * Get the path of a file by id
875
+     *
876
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
877
+     *
878
+     * @param int $id
879
+     * @throws NotFoundException
880
+     * @return string
881
+     */
882
+    public static function getPath($id) {
883
+        return self::$defaultInstance->getPath($id);
884
+    }
885
+
886
+    /**
887
+     * Get the owner for a file or folder
888
+     *
889
+     * @param string $path
890
+     * @return string
891
+     */
892
+    public static function getOwner($path) {
893
+        return self::$defaultInstance->getOwner($path);
894
+    }
895
+
896
+    /**
897
+     * get the ETag for a file or folder
898
+     *
899
+     * @param string $path
900
+     * @return string
901
+     */
902
+    static public function getETag($path) {
903
+        return self::$defaultInstance->getETag($path);
904
+    }
905 905
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -405,8 +405,8 @@  discard block
 block discarded – undo
405 405
 		$userObject = $userManager->get($user);
406 406
 
407 407
 		if (is_null($userObject)) {
408
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
409
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
408
+			\OCP\Util::writeLog('files', ' Backends provided no user object for '.$user, \OCP\Util::ERROR);
409
+			throw new \OC\User\NoUserException('Backends provided no user object for '.$user);
410 410
 		}
411 411
 
412 412
 		self::$usersSetup[$user] = true;
@@ -442,7 +442,7 @@  discard block
 block discarded – undo
442 442
 	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
443 443
 		if (!self::$listeningForProviders) {
444 444
 			self::$listeningForProviders = true;
445
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
445
+			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function(IMountProvider $provider) use ($userManager) {
446 446
 				foreach (Filesystem::$usersSetup as $user => $setup) {
447 447
 					$userObject = $userManager->get($user);
448 448
 					if ($userObject) {
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
 	 * @return string
538 538
 	 */
539 539
 	static public function getLocalPath($path) {
540
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
540
+		$datadir = \OC_User::getHome(\OC_User::getUser()).'/files';
541 541
 		$newpath = $path;
542 542
 		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
543 543
 			$newpath = substr($path, strlen($datadir));
@@ -554,7 +554,7 @@  discard block
 block discarded – undo
554 554
 	static public function isValidPath($path) {
555 555
 		$path = self::normalizePath($path);
556 556
 		if (!$path || $path[0] !== '/') {
557
-			$path = '/' . $path;
557
+			$path = '/'.$path;
558 558
 		}
559 559
 		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
560 560
 			return false;
@@ -783,7 +783,7 @@  discard block
 block discarded – undo
783 783
 		 *        conversion should get removed as soon as all existing
784 784
 		 *        function calls have been fixed.
785 785
 		 */
786
-		$path = (string)$path;
786
+		$path = (string) $path;
787 787
 
788 788
 		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
789 789
 
@@ -805,7 +805,7 @@  discard block
 block discarded – undo
805 805
 
806 806
 		//add leading slash
807 807
 		if ($path[0] !== '/') {
808
-			$path = '/' . $path;
808
+			$path = '/'.$path;
809 809
 		}
810 810
 
811 811
 		// remove '/./'
Please login to merge, or discard this patch.
lib/private/Files/Node/LazyRoot.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@
 block discarded – undo
52 52
 	 * Magic method to first get the real rootFolder and then
53 53
 	 * call $method with $args on it
54 54
 	 *
55
-	 * @param $method
55
+	 * @param string $method
56 56
 	 * @param $args
57 57
 	 * @return mixed
58 58
 	 */
Please login to merge, or discard this patch.
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -20,9 +20,7 @@
 block discarded – undo
20 20
  */
21 21
 namespace OC\Files\Node;
22 22
 
23
-use OC\Files\Mount\MountPoint;
24 23
 use OCP\Files\IRootFolder;
25
-use OCP\Files\NotPermittedException;
26 24
 
27 25
 /**
28 26
  * Class LazyRoot
Please login to merge, or discard this patch.
Indentation   +436 added lines, -436 removed lines patch added patch discarded remove patch
@@ -34,442 +34,442 @@
 block discarded – undo
34 34
  * @package OC\Files\Node
35 35
  */
36 36
 class LazyRoot implements IRootFolder {
37
-	/** @var \Closure */
38
-	private $rootFolderClosure;
39
-
40
-	/** @var IRootFolder */
41
-	private $rootFolder;
42
-
43
-	/**
44
-	 * LazyRoot constructor.
45
-	 *
46
-	 * @param \Closure $rootFolderClosure
47
-	 */
48
-	public function __construct(\Closure $rootFolderClosure) {
49
-		$this->rootFolderClosure = $rootFolderClosure;
50
-	}
51
-
52
-	/**
53
-	 * Magic method to first get the real rootFolder and then
54
-	 * call $method with $args on it
55
-	 *
56
-	 * @param $method
57
-	 * @param $args
58
-	 * @return mixed
59
-	 */
60
-	public function __call($method, $args) {
61
-		if ($this->rootFolder === null) {
62
-			$this->rootFolder = call_user_func($this->rootFolderClosure);
63
-		}
64
-
65
-		return call_user_func_array([$this->rootFolder, $method], $args);
66
-	}
67
-
68
-	/**
69
-	 * @inheritDoc
70
-	 */
71
-	public function getUser() {
72
-		return $this->__call(__FUNCTION__, func_get_args());
73
-	}
74
-
75
-	/**
76
-	 * @inheritDoc
77
-	 */
78
-	public function listen($scope, $method, callable $callback) {
79
-		$this->__call(__FUNCTION__, func_get_args());
80
-	}
81
-
82
-	/**
83
-	 * @inheritDoc
84
-	 */
85
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
86
-		$this->__call(__FUNCTION__, func_get_args());
87
-	}
88
-
89
-	/**
90
-	 * @inheritDoc
91
-	 */
92
-	public function emit($scope, $method, $arguments = array()) {
93
-		$this->__call(__FUNCTION__, func_get_args());
94
-	}
95
-
96
-	/**
97
-	 * @inheritDoc
98
-	 */
99
-	public function mount($storage, $mountPoint, $arguments = array()) {
100
-		$this->__call(__FUNCTION__, func_get_args());
101
-	}
102
-
103
-	/**
104
-	 * @inheritDoc
105
-	 */
106
-	public function getMount($mountPoint) {
107
-		return $this->__call(__FUNCTION__, func_get_args());
108
-	}
109
-
110
-	/**
111
-	 * @inheritDoc
112
-	 */
113
-	public function getMountsIn($mountPoint) {
114
-		return $this->__call(__FUNCTION__, func_get_args());
115
-	}
116
-
117
-	/**
118
-	 * @inheritDoc
119
-	 */
120
-	public function getMountByStorageId($storageId) {
121
-		return $this->__call(__FUNCTION__, func_get_args());
122
-	}
123
-
124
-	/**
125
-	 * @inheritDoc
126
-	 */
127
-	public function getMountByNumericStorageId($numericId) {
128
-		return $this->__call(__FUNCTION__, func_get_args());
129
-	}
130
-
131
-	/**
132
-	 * @inheritDoc
133
-	 */
134
-	public function unMount($mount) {
135
-		$this->__call(__FUNCTION__, func_get_args());
136
-	}
137
-
138
-	/**
139
-	 * @inheritDoc
140
-	 */
141
-	public function get($path) {
142
-		return $this->__call(__FUNCTION__, func_get_args());
143
-	}
144
-
145
-	/**
146
-	 * @inheritDoc
147
-	 */
148
-	public function rename($targetPath) {
149
-		return $this->__call(__FUNCTION__, func_get_args());
150
-	}
151
-
152
-	/**
153
-	 * @inheritDoc
154
-	 */
155
-	public function delete() {
156
-		return $this->__call(__FUNCTION__, func_get_args());
157
-	}
158
-
159
-	/**
160
-	 * @inheritDoc
161
-	 */
162
-	public function copy($targetPath) {
163
-		return $this->__call(__FUNCTION__, func_get_args());
164
-	}
165
-
166
-	/**
167
-	 * @inheritDoc
168
-	 */
169
-	public function touch($mtime = null) {
170
-		$this->__call(__FUNCTION__, func_get_args());
171
-	}
172
-
173
-	/**
174
-	 * @inheritDoc
175
-	 */
176
-	public function getStorage() {
177
-		return $this->__call(__FUNCTION__, func_get_args());
178
-	}
179
-
180
-	/**
181
-	 * @inheritDoc
182
-	 */
183
-	public function getPath() {
184
-		return $this->__call(__FUNCTION__, func_get_args());
185
-	}
186
-
187
-	/**
188
-	 * @inheritDoc
189
-	 */
190
-	public function getInternalPath() {
191
-		return $this->__call(__FUNCTION__, func_get_args());
192
-	}
193
-
194
-	/**
195
-	 * @inheritDoc
196
-	 */
197
-	public function getId() {
198
-		return $this->__call(__FUNCTION__, func_get_args());
199
-	}
200
-
201
-	/**
202
-	 * @inheritDoc
203
-	 */
204
-	public function stat() {
205
-		return $this->__call(__FUNCTION__, func_get_args());
206
-	}
207
-
208
-	/**
209
-	 * @inheritDoc
210
-	 */
211
-	public function getMTime() {
212
-		return $this->__call(__FUNCTION__, func_get_args());
213
-	}
214
-
215
-	/**
216
-	 * @inheritDoc
217
-	 */
218
-	public function getSize() {
219
-		return $this->__call(__FUNCTION__, func_get_args());
220
-	}
221
-
222
-	/**
223
-	 * @inheritDoc
224
-	 */
225
-	public function getEtag() {
226
-		return $this->__call(__FUNCTION__, func_get_args());
227
-	}
228
-
229
-	/**
230
-	 * @inheritDoc
231
-	 */
232
-	public function getPermissions() {
233
-		return $this->__call(__FUNCTION__, func_get_args());
234
-	}
235
-
236
-	/**
237
-	 * @inheritDoc
238
-	 */
239
-	public function isReadable() {
240
-		return $this->__call(__FUNCTION__, func_get_args());
241
-	}
242
-
243
-	/**
244
-	 * @inheritDoc
245
-	 */
246
-	public function isUpdateable() {
247
-		return $this->__call(__FUNCTION__, func_get_args());
248
-	}
249
-
250
-	/**
251
-	 * @inheritDoc
252
-	 */
253
-	public function isDeletable() {
254
-		return $this->__call(__FUNCTION__, func_get_args());
255
-	}
256
-
257
-	/**
258
-	 * @inheritDoc
259
-	 */
260
-	public function isShareable() {
261
-		return $this->__call(__FUNCTION__, func_get_args());
262
-	}
263
-
264
-	/**
265
-	 * @inheritDoc
266
-	 */
267
-	public function getParent() {
268
-		return $this->__call(__FUNCTION__, func_get_args());
269
-	}
270
-
271
-	/**
272
-	 * @inheritDoc
273
-	 */
274
-	public function getName() {
275
-		return $this->__call(__FUNCTION__, func_get_args());
276
-	}
277
-
278
-	/**
279
-	 * @inheritDoc
280
-	 */
281
-	public function getUserFolder($userId) {
282
-		return $this->__call(__FUNCTION__, func_get_args());
283
-	}
284
-
285
-	/**
286
-	 * @inheritDoc
287
-	 */
288
-	public function getMimetype() {
289
-		return $this->__call(__FUNCTION__, func_get_args());
290
-	}
291
-
292
-	/**
293
-	 * @inheritDoc
294
-	 */
295
-	public function getMimePart() {
296
-		return $this->__call(__FUNCTION__, func_get_args());
297
-	}
298
-
299
-	/**
300
-	 * @inheritDoc
301
-	 */
302
-	public function isEncrypted() {
303
-		return $this->__call(__FUNCTION__, func_get_args());
304
-	}
305
-
306
-	/**
307
-	 * @inheritDoc
308
-	 */
309
-	public function getType() {
310
-		return $this->__call(__FUNCTION__, func_get_args());
311
-	}
312
-
313
-	/**
314
-	 * @inheritDoc
315
-	 */
316
-	public function isShared() {
317
-		return $this->__call(__FUNCTION__, func_get_args());
318
-	}
319
-
320
-	/**
321
-	 * @inheritDoc
322
-	 */
323
-	public function isMounted() {
324
-		return $this->__call(__FUNCTION__, func_get_args());
325
-	}
326
-
327
-	/**
328
-	 * @inheritDoc
329
-	 */
330
-	public function getMountPoint() {
331
-		return $this->__call(__FUNCTION__, func_get_args());
332
-	}
333
-
334
-	/**
335
-	 * @inheritDoc
336
-	 */
337
-	public function getOwner() {
338
-		return $this->__call(__FUNCTION__, func_get_args());
339
-	}
340
-
341
-	/**
342
-	 * @inheritDoc
343
-	 */
344
-	public function getChecksum() {
345
-		return $this->__call(__FUNCTION__, func_get_args());
346
-	}
347
-
348
-	/**
349
-	 * @inheritDoc
350
-	 */
351
-	public function getFullPath($path) {
352
-		return $this->__call(__FUNCTION__, func_get_args());
353
-	}
354
-
355
-	/**
356
-	 * @inheritDoc
357
-	 */
358
-	public function getRelativePath($path) {
359
-		return $this->__call(__FUNCTION__, func_get_args());
360
-	}
361
-
362
-	/**
363
-	 * @inheritDoc
364
-	 */
365
-	public function isSubNode($node) {
366
-		return $this->__call(__FUNCTION__, func_get_args());
367
-	}
368
-
369
-	/**
370
-	 * @inheritDoc
371
-	 */
372
-	public function getDirectoryListing() {
373
-		return $this->__call(__FUNCTION__, func_get_args());
374
-	}
375
-
376
-	/**
377
-	 * @inheritDoc
378
-	 */
379
-	public function nodeExists($path) {
380
-		return $this->__call(__FUNCTION__, func_get_args());
381
-	}
382
-
383
-	/**
384
-	 * @inheritDoc
385
-	 */
386
-	public function newFolder($path) {
387
-		return $this->__call(__FUNCTION__, func_get_args());
388
-	}
389
-
390
-	/**
391
-	 * @inheritDoc
392
-	 */
393
-	public function newFile($path) {
394
-		return $this->__call(__FUNCTION__, func_get_args());
395
-	}
396
-
397
-	/**
398
-	 * @inheritDoc
399
-	 */
400
-	public function search($query) {
401
-		return $this->__call(__FUNCTION__, func_get_args());
402
-	}
403
-
404
-	/**
405
-	 * @inheritDoc
406
-	 */
407
-	public function searchByMime($mimetype) {
408
-		return $this->__call(__FUNCTION__, func_get_args());
409
-	}
410
-
411
-	/**
412
-	 * @inheritDoc
413
-	 */
414
-	public function searchByTag($tag, $userId) {
415
-		return $this->__call(__FUNCTION__, func_get_args());
416
-	}
417
-
418
-	/**
419
-	 * @inheritDoc
420
-	 */
421
-	public function getById($id) {
422
-		return $this->__call(__FUNCTION__, func_get_args());
423
-	}
424
-
425
-	/**
426
-	 * @inheritDoc
427
-	 */
428
-	public function getFreeSpace() {
429
-		return $this->__call(__FUNCTION__, func_get_args());
430
-	}
431
-
432
-	/**
433
-	 * @inheritDoc
434
-	 */
435
-	public function isCreatable() {
436
-		return $this->__call(__FUNCTION__, func_get_args());
437
-	}
438
-
439
-	/**
440
-	 * @inheritDoc
441
-	 */
442
-	public function getNonExistingName($name) {
443
-		return $this->__call(__FUNCTION__, func_get_args());
444
-	}
445
-
446
-	/**
447
-	 * @inheritDoc
448
-	 */
449
-	public function move($targetPath) {
450
-		return $this->__call(__FUNCTION__, func_get_args());
451
-	}
452
-
453
-	/**
454
-	 * @inheritDoc
455
-	 */
456
-	public function lock($type) {
457
-		return $this->__call(__FUNCTION__, func_get_args());
458
-	}
459
-
460
-	/**
461
-	 * @inheritDoc
462
-	 */
463
-	public function changeLock($targetType) {
464
-		return $this->__call(__FUNCTION__, func_get_args());
465
-	}
466
-
467
-	/**
468
-	 * @inheritDoc
469
-	 */
470
-	public function unlock($type) {
471
-		return $this->__call(__FUNCTION__, func_get_args());
472
-	}
37
+    /** @var \Closure */
38
+    private $rootFolderClosure;
39
+
40
+    /** @var IRootFolder */
41
+    private $rootFolder;
42
+
43
+    /**
44
+     * LazyRoot constructor.
45
+     *
46
+     * @param \Closure $rootFolderClosure
47
+     */
48
+    public function __construct(\Closure $rootFolderClosure) {
49
+        $this->rootFolderClosure = $rootFolderClosure;
50
+    }
51
+
52
+    /**
53
+     * Magic method to first get the real rootFolder and then
54
+     * call $method with $args on it
55
+     *
56
+     * @param $method
57
+     * @param $args
58
+     * @return mixed
59
+     */
60
+    public function __call($method, $args) {
61
+        if ($this->rootFolder === null) {
62
+            $this->rootFolder = call_user_func($this->rootFolderClosure);
63
+        }
64
+
65
+        return call_user_func_array([$this->rootFolder, $method], $args);
66
+    }
67
+
68
+    /**
69
+     * @inheritDoc
70
+     */
71
+    public function getUser() {
72
+        return $this->__call(__FUNCTION__, func_get_args());
73
+    }
74
+
75
+    /**
76
+     * @inheritDoc
77
+     */
78
+    public function listen($scope, $method, callable $callback) {
79
+        $this->__call(__FUNCTION__, func_get_args());
80
+    }
81
+
82
+    /**
83
+     * @inheritDoc
84
+     */
85
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
86
+        $this->__call(__FUNCTION__, func_get_args());
87
+    }
88
+
89
+    /**
90
+     * @inheritDoc
91
+     */
92
+    public function emit($scope, $method, $arguments = array()) {
93
+        $this->__call(__FUNCTION__, func_get_args());
94
+    }
95
+
96
+    /**
97
+     * @inheritDoc
98
+     */
99
+    public function mount($storage, $mountPoint, $arguments = array()) {
100
+        $this->__call(__FUNCTION__, func_get_args());
101
+    }
102
+
103
+    /**
104
+     * @inheritDoc
105
+     */
106
+    public function getMount($mountPoint) {
107
+        return $this->__call(__FUNCTION__, func_get_args());
108
+    }
109
+
110
+    /**
111
+     * @inheritDoc
112
+     */
113
+    public function getMountsIn($mountPoint) {
114
+        return $this->__call(__FUNCTION__, func_get_args());
115
+    }
116
+
117
+    /**
118
+     * @inheritDoc
119
+     */
120
+    public function getMountByStorageId($storageId) {
121
+        return $this->__call(__FUNCTION__, func_get_args());
122
+    }
123
+
124
+    /**
125
+     * @inheritDoc
126
+     */
127
+    public function getMountByNumericStorageId($numericId) {
128
+        return $this->__call(__FUNCTION__, func_get_args());
129
+    }
130
+
131
+    /**
132
+     * @inheritDoc
133
+     */
134
+    public function unMount($mount) {
135
+        $this->__call(__FUNCTION__, func_get_args());
136
+    }
137
+
138
+    /**
139
+     * @inheritDoc
140
+     */
141
+    public function get($path) {
142
+        return $this->__call(__FUNCTION__, func_get_args());
143
+    }
144
+
145
+    /**
146
+     * @inheritDoc
147
+     */
148
+    public function rename($targetPath) {
149
+        return $this->__call(__FUNCTION__, func_get_args());
150
+    }
151
+
152
+    /**
153
+     * @inheritDoc
154
+     */
155
+    public function delete() {
156
+        return $this->__call(__FUNCTION__, func_get_args());
157
+    }
158
+
159
+    /**
160
+     * @inheritDoc
161
+     */
162
+    public function copy($targetPath) {
163
+        return $this->__call(__FUNCTION__, func_get_args());
164
+    }
165
+
166
+    /**
167
+     * @inheritDoc
168
+     */
169
+    public function touch($mtime = null) {
170
+        $this->__call(__FUNCTION__, func_get_args());
171
+    }
172
+
173
+    /**
174
+     * @inheritDoc
175
+     */
176
+    public function getStorage() {
177
+        return $this->__call(__FUNCTION__, func_get_args());
178
+    }
179
+
180
+    /**
181
+     * @inheritDoc
182
+     */
183
+    public function getPath() {
184
+        return $this->__call(__FUNCTION__, func_get_args());
185
+    }
186
+
187
+    /**
188
+     * @inheritDoc
189
+     */
190
+    public function getInternalPath() {
191
+        return $this->__call(__FUNCTION__, func_get_args());
192
+    }
193
+
194
+    /**
195
+     * @inheritDoc
196
+     */
197
+    public function getId() {
198
+        return $this->__call(__FUNCTION__, func_get_args());
199
+    }
200
+
201
+    /**
202
+     * @inheritDoc
203
+     */
204
+    public function stat() {
205
+        return $this->__call(__FUNCTION__, func_get_args());
206
+    }
207
+
208
+    /**
209
+     * @inheritDoc
210
+     */
211
+    public function getMTime() {
212
+        return $this->__call(__FUNCTION__, func_get_args());
213
+    }
214
+
215
+    /**
216
+     * @inheritDoc
217
+     */
218
+    public function getSize() {
219
+        return $this->__call(__FUNCTION__, func_get_args());
220
+    }
221
+
222
+    /**
223
+     * @inheritDoc
224
+     */
225
+    public function getEtag() {
226
+        return $this->__call(__FUNCTION__, func_get_args());
227
+    }
228
+
229
+    /**
230
+     * @inheritDoc
231
+     */
232
+    public function getPermissions() {
233
+        return $this->__call(__FUNCTION__, func_get_args());
234
+    }
235
+
236
+    /**
237
+     * @inheritDoc
238
+     */
239
+    public function isReadable() {
240
+        return $this->__call(__FUNCTION__, func_get_args());
241
+    }
242
+
243
+    /**
244
+     * @inheritDoc
245
+     */
246
+    public function isUpdateable() {
247
+        return $this->__call(__FUNCTION__, func_get_args());
248
+    }
249
+
250
+    /**
251
+     * @inheritDoc
252
+     */
253
+    public function isDeletable() {
254
+        return $this->__call(__FUNCTION__, func_get_args());
255
+    }
256
+
257
+    /**
258
+     * @inheritDoc
259
+     */
260
+    public function isShareable() {
261
+        return $this->__call(__FUNCTION__, func_get_args());
262
+    }
263
+
264
+    /**
265
+     * @inheritDoc
266
+     */
267
+    public function getParent() {
268
+        return $this->__call(__FUNCTION__, func_get_args());
269
+    }
270
+
271
+    /**
272
+     * @inheritDoc
273
+     */
274
+    public function getName() {
275
+        return $this->__call(__FUNCTION__, func_get_args());
276
+    }
277
+
278
+    /**
279
+     * @inheritDoc
280
+     */
281
+    public function getUserFolder($userId) {
282
+        return $this->__call(__FUNCTION__, func_get_args());
283
+    }
284
+
285
+    /**
286
+     * @inheritDoc
287
+     */
288
+    public function getMimetype() {
289
+        return $this->__call(__FUNCTION__, func_get_args());
290
+    }
291
+
292
+    /**
293
+     * @inheritDoc
294
+     */
295
+    public function getMimePart() {
296
+        return $this->__call(__FUNCTION__, func_get_args());
297
+    }
298
+
299
+    /**
300
+     * @inheritDoc
301
+     */
302
+    public function isEncrypted() {
303
+        return $this->__call(__FUNCTION__, func_get_args());
304
+    }
305
+
306
+    /**
307
+     * @inheritDoc
308
+     */
309
+    public function getType() {
310
+        return $this->__call(__FUNCTION__, func_get_args());
311
+    }
312
+
313
+    /**
314
+     * @inheritDoc
315
+     */
316
+    public function isShared() {
317
+        return $this->__call(__FUNCTION__, func_get_args());
318
+    }
319
+
320
+    /**
321
+     * @inheritDoc
322
+     */
323
+    public function isMounted() {
324
+        return $this->__call(__FUNCTION__, func_get_args());
325
+    }
326
+
327
+    /**
328
+     * @inheritDoc
329
+     */
330
+    public function getMountPoint() {
331
+        return $this->__call(__FUNCTION__, func_get_args());
332
+    }
333
+
334
+    /**
335
+     * @inheritDoc
336
+     */
337
+    public function getOwner() {
338
+        return $this->__call(__FUNCTION__, func_get_args());
339
+    }
340
+
341
+    /**
342
+     * @inheritDoc
343
+     */
344
+    public function getChecksum() {
345
+        return $this->__call(__FUNCTION__, func_get_args());
346
+    }
347
+
348
+    /**
349
+     * @inheritDoc
350
+     */
351
+    public function getFullPath($path) {
352
+        return $this->__call(__FUNCTION__, func_get_args());
353
+    }
354
+
355
+    /**
356
+     * @inheritDoc
357
+     */
358
+    public function getRelativePath($path) {
359
+        return $this->__call(__FUNCTION__, func_get_args());
360
+    }
361
+
362
+    /**
363
+     * @inheritDoc
364
+     */
365
+    public function isSubNode($node) {
366
+        return $this->__call(__FUNCTION__, func_get_args());
367
+    }
368
+
369
+    /**
370
+     * @inheritDoc
371
+     */
372
+    public function getDirectoryListing() {
373
+        return $this->__call(__FUNCTION__, func_get_args());
374
+    }
375
+
376
+    /**
377
+     * @inheritDoc
378
+     */
379
+    public function nodeExists($path) {
380
+        return $this->__call(__FUNCTION__, func_get_args());
381
+    }
382
+
383
+    /**
384
+     * @inheritDoc
385
+     */
386
+    public function newFolder($path) {
387
+        return $this->__call(__FUNCTION__, func_get_args());
388
+    }
389
+
390
+    /**
391
+     * @inheritDoc
392
+     */
393
+    public function newFile($path) {
394
+        return $this->__call(__FUNCTION__, func_get_args());
395
+    }
396
+
397
+    /**
398
+     * @inheritDoc
399
+     */
400
+    public function search($query) {
401
+        return $this->__call(__FUNCTION__, func_get_args());
402
+    }
403
+
404
+    /**
405
+     * @inheritDoc
406
+     */
407
+    public function searchByMime($mimetype) {
408
+        return $this->__call(__FUNCTION__, func_get_args());
409
+    }
410
+
411
+    /**
412
+     * @inheritDoc
413
+     */
414
+    public function searchByTag($tag, $userId) {
415
+        return $this->__call(__FUNCTION__, func_get_args());
416
+    }
417
+
418
+    /**
419
+     * @inheritDoc
420
+     */
421
+    public function getById($id) {
422
+        return $this->__call(__FUNCTION__, func_get_args());
423
+    }
424
+
425
+    /**
426
+     * @inheritDoc
427
+     */
428
+    public function getFreeSpace() {
429
+        return $this->__call(__FUNCTION__, func_get_args());
430
+    }
431
+
432
+    /**
433
+     * @inheritDoc
434
+     */
435
+    public function isCreatable() {
436
+        return $this->__call(__FUNCTION__, func_get_args());
437
+    }
438
+
439
+    /**
440
+     * @inheritDoc
441
+     */
442
+    public function getNonExistingName($name) {
443
+        return $this->__call(__FUNCTION__, func_get_args());
444
+    }
445
+
446
+    /**
447
+     * @inheritDoc
448
+     */
449
+    public function move($targetPath) {
450
+        return $this->__call(__FUNCTION__, func_get_args());
451
+    }
452
+
453
+    /**
454
+     * @inheritDoc
455
+     */
456
+    public function lock($type) {
457
+        return $this->__call(__FUNCTION__, func_get_args());
458
+    }
459
+
460
+    /**
461
+     * @inheritDoc
462
+     */
463
+    public function changeLock($targetType) {
464
+        return $this->__call(__FUNCTION__, func_get_args());
465
+    }
466
+
467
+    /**
468
+     * @inheritDoc
469
+     */
470
+    public function unlock($type) {
471
+        return $this->__call(__FUNCTION__, func_get_args());
472
+    }
473 473
 
474 474
 
475 475
 }
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/ObjectStoreStorage.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -160,6 +160,9 @@
 block discarded – undo
160 160
 		return true;
161 161
 	}
162 162
 
163
+	/**
164
+	 * @param string $path
165
+	 */
163 166
 	private function rmObjects($path) {
164 167
 		$children = $this->getCache()->getFolderContents($path);
165 168
 		foreach ($children as $child) {
Please login to merge, or discard this patch.
Indentation   +374 added lines, -374 removed lines patch added patch discarded remove patch
@@ -31,378 +31,378 @@
 block discarded – undo
31 31
 
32 32
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
33 33
 
34
-	/**
35
-	 * @var array
36
-	 */
37
-	private static $tmpFiles = array();
38
-	/**
39
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
40
-	 */
41
-	protected $objectStore;
42
-	/**
43
-	 * @var string $id
44
-	 */
45
-	protected $id;
46
-	/**
47
-	 * @var \OC\User\User $user
48
-	 */
49
-	protected $user;
50
-
51
-	public function __construct($params) {
52
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
-			$this->objectStore = $params['objectstore'];
54
-		} else {
55
-			throw new \Exception('missing IObjectStore instance');
56
-		}
57
-		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
59
-		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
61
-		}
62
-		//initialize cache with root directory in cache
63
-		if (!$this->is_dir('/')) {
64
-			$this->mkdir('/');
65
-		}
66
-	}
67
-
68
-	public function mkdir($path) {
69
-		$path = $this->normalizePath($path);
70
-
71
-		if ($this->file_exists($path)) {
72
-			return false;
73
-		}
74
-
75
-		$mTime = time();
76
-		$data = [
77
-			'mimetype' => 'httpd/unix-directory',
78
-			'size' => 0,
79
-			'mtime' => $mTime,
80
-			'storage_mtime' => $mTime,
81
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
82
-		];
83
-		if ($path === '') {
84
-			//create root on the fly
85
-			$data['etag'] = $this->getETag('');
86
-			$this->getCache()->put('', $data);
87
-			return true;
88
-		} else {
89
-			// if parent does not exist, create it
90
-			$parent = $this->normalizePath(dirname($path));
91
-			$parentType = $this->filetype($parent);
92
-			if ($parentType === false) {
93
-				if (!$this->mkdir($parent)) {
94
-					// something went wrong
95
-					return false;
96
-				}
97
-			} else if ($parentType === 'file') {
98
-				// parent is a file
99
-				return false;
100
-			}
101
-			// finally create the new dir
102
-			$mTime = time(); // update mtime
103
-			$data['mtime'] = $mTime;
104
-			$data['storage_mtime'] = $mTime;
105
-			$data['etag'] = $this->getETag($path);
106
-			$this->getCache()->put($path, $data);
107
-			return true;
108
-		}
109
-	}
110
-
111
-	/**
112
-	 * @param string $path
113
-	 * @return string
114
-	 */
115
-	private function normalizePath($path) {
116
-		$path = trim($path, '/');
117
-		//FIXME why do we sometimes get a path like 'files//username'?
118
-		$path = str_replace('//', '/', $path);
119
-
120
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
121
-		if (!$path || $path === '.') {
122
-			$path = '';
123
-		}
124
-
125
-		return $path;
126
-	}
127
-
128
-	/**
129
-	 * Object Stores use a NoopScanner because metadata is directly stored in
130
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
131
-	 *
132
-	 * @param string $path
133
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
134
-	 * @return \OC\Files\ObjectStore\NoopScanner
135
-	 */
136
-	public function getScanner($path = '', $storage = null) {
137
-		if (!$storage) {
138
-			$storage = $this;
139
-		}
140
-		if (!isset($this->scanner)) {
141
-			$this->scanner = new NoopScanner($storage);
142
-		}
143
-		return $this->scanner;
144
-	}
145
-
146
-	public function getId() {
147
-		return $this->id;
148
-	}
149
-
150
-	public function rmdir($path) {
151
-		$path = $this->normalizePath($path);
152
-
153
-		if (!$this->is_dir($path)) {
154
-			return false;
155
-		}
156
-
157
-		$this->rmObjects($path);
158
-
159
-		$this->getCache()->remove($path);
160
-
161
-		return true;
162
-	}
163
-
164
-	private function rmObjects($path) {
165
-		$children = $this->getCache()->getFolderContents($path);
166
-		foreach ($children as $child) {
167
-			if ($child['mimetype'] === 'httpd/unix-directory') {
168
-				$this->rmObjects($child['path']);
169
-			} else {
170
-				$this->unlink($child['path']);
171
-			}
172
-		}
173
-	}
174
-
175
-	public function unlink($path) {
176
-		$path = $this->normalizePath($path);
177
-		$stat = $this->stat($path);
178
-
179
-		if ($stat && isset($stat['fileid'])) {
180
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
181
-				return $this->rmdir($path);
182
-			}
183
-			try {
184
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
185
-			} catch (\Exception $ex) {
186
-				if ($ex->getCode() !== 404) {
187
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
188
-					return false;
189
-				} else {
190
-					//removing from cache is ok as it does not exist in the objectstore anyway
191
-				}
192
-			}
193
-			$this->getCache()->remove($path);
194
-			return true;
195
-		}
196
-		return false;
197
-	}
198
-
199
-	public function stat($path) {
200
-		$path = $this->normalizePath($path);
201
-		$cacheEntry = $this->getCache()->get($path);
202
-		if ($cacheEntry instanceof CacheEntry) {
203
-			return $cacheEntry->getData();
204
-		} else {
205
-			return false;
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
211
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
212
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
213
-	 *
214
-	 * @param int $fileId the fileid
215
-	 * @return null|string the unified resource name used to identify the object
216
-	 */
217
-	protected function getURN($fileId) {
218
-		if (is_numeric($fileId)) {
219
-			return 'urn:oid:' . $fileId;
220
-		}
221
-		return null;
222
-	}
223
-
224
-	public function opendir($path) {
225
-		$path = $this->normalizePath($path);
226
-
227
-		try {
228
-			$files = array();
229
-			$folderContents = $this->getCache()->getFolderContents($path);
230
-			foreach ($folderContents as $file) {
231
-				$files[] = $file['name'];
232
-			}
233
-
234
-			return IteratorDirectory::wrap($files);
235
-		} catch (\Exception $e) {
236
-			\OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
237
-			return false;
238
-		}
239
-	}
240
-
241
-	public function filetype($path) {
242
-		$path = $this->normalizePath($path);
243
-		$stat = $this->stat($path);
244
-		if ($stat) {
245
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
246
-				return 'dir';
247
-			}
248
-			return 'file';
249
-		} else {
250
-			return false;
251
-		}
252
-	}
253
-
254
-	public function fopen($path, $mode) {
255
-		$path = $this->normalizePath($path);
256
-
257
-		switch ($mode) {
258
-			case 'r':
259
-			case 'rb':
260
-				$stat = $this->stat($path);
261
-				if (is_array($stat)) {
262
-					try {
263
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
264
-					} catch (\Exception $ex) {
265
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
266
-						return false;
267
-					}
268
-				} else {
269
-					return false;
270
-				}
271
-			case 'w':
272
-			case 'wb':
273
-			case 'a':
274
-			case 'ab':
275
-			case 'r+':
276
-			case 'w+':
277
-			case 'wb+':
278
-			case 'a+':
279
-			case 'x':
280
-			case 'x+':
281
-			case 'c':
282
-			case 'c+':
283
-				if (strrpos($path, '.') !== false) {
284
-					$ext = substr($path, strrpos($path, '.'));
285
-				} else {
286
-					$ext = '';
287
-				}
288
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
289
-				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
290
-				if ($this->file_exists($path)) {
291
-					$source = $this->fopen($path, 'r');
292
-					file_put_contents($tmpFile, $source);
293
-				}
294
-				self::$tmpFiles[$tmpFile] = $path;
295
-
296
-				return fopen('close://' . $tmpFile, $mode);
297
-		}
298
-		return false;
299
-	}
300
-
301
-	public function file_exists($path) {
302
-		$path = $this->normalizePath($path);
303
-		return (bool)$this->stat($path);
304
-	}
305
-
306
-	public function rename($source, $target) {
307
-		$source = $this->normalizePath($source);
308
-		$target = $this->normalizePath($target);
309
-		$this->remove($target);
310
-		$this->getCache()->move($source, $target);
311
-		$this->touch(dirname($target));
312
-		return true;
313
-	}
314
-
315
-	public function getMimeType($path) {
316
-		$path = $this->normalizePath($path);
317
-		$stat = $this->stat($path);
318
-		if (is_array($stat)) {
319
-			return $stat['mimetype'];
320
-		} else {
321
-			return false;
322
-		}
323
-	}
324
-
325
-	public function touch($path, $mtime = null) {
326
-		if (is_null($mtime)) {
327
-			$mtime = time();
328
-		}
329
-
330
-		$path = $this->normalizePath($path);
331
-		$dirName = dirname($path);
332
-		$parentExists = $this->is_dir($dirName);
333
-		if (!$parentExists) {
334
-			return false;
335
-		}
336
-
337
-		$stat = $this->stat($path);
338
-		if (is_array($stat)) {
339
-			// update existing mtime in db
340
-			$stat['mtime'] = $mtime;
341
-			$this->getCache()->update($stat['fileid'], $stat);
342
-		} else {
343
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
344
-			// create new file
345
-			$stat = array(
346
-				'etag' => $this->getETag($path),
347
-				'mimetype' => $mimeType,
348
-				'size' => 0,
349
-				'mtime' => $mtime,
350
-				'storage_mtime' => $mtime,
351
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
352
-			);
353
-			$fileId = $this->getCache()->put($path, $stat);
354
-			try {
355
-				//read an empty file from memory
356
-				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
357
-			} catch (\Exception $ex) {
358
-				$this->getCache()->remove($path);
359
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
360
-				return false;
361
-			}
362
-		}
363
-		return true;
364
-	}
365
-
366
-	public function writeBack($tmpFile) {
367
-		if (!isset(self::$tmpFiles[$tmpFile])) {
368
-			return;
369
-		}
370
-
371
-		$path = self::$tmpFiles[$tmpFile];
372
-		$stat = $this->stat($path);
373
-		if (empty($stat)) {
374
-			// create new file
375
-			$stat = array(
376
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
377
-			);
378
-		}
379
-		// update stat with new data
380
-		$mTime = time();
381
-		$stat['size'] = filesize($tmpFile);
382
-		$stat['mtime'] = $mTime;
383
-		$stat['storage_mtime'] = $mTime;
384
-		$stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
385
-		$stat['etag'] = $this->getETag($path);
386
-
387
-		$fileId = $this->getCache()->put($path, $stat);
388
-		try {
389
-			//upload to object storage
390
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
391
-		} catch (\Exception $ex) {
392
-			$this->getCache()->remove($path);
393
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
394
-			throw $ex; // make this bubble up
395
-		}
396
-	}
397
-
398
-	/**
399
-	 * external changes are not supported, exclusive access to the object storage is assumed
400
-	 *
401
-	 * @param string $path
402
-	 * @param int $time
403
-	 * @return false
404
-	 */
405
-	public function hasUpdated($path, $time) {
406
-		return false;
407
-	}
34
+    /**
35
+     * @var array
36
+     */
37
+    private static $tmpFiles = array();
38
+    /**
39
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
40
+     */
41
+    protected $objectStore;
42
+    /**
43
+     * @var string $id
44
+     */
45
+    protected $id;
46
+    /**
47
+     * @var \OC\User\User $user
48
+     */
49
+    protected $user;
50
+
51
+    public function __construct($params) {
52
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
+            $this->objectStore = $params['objectstore'];
54
+        } else {
55
+            throw new \Exception('missing IObjectStore instance');
56
+        }
57
+        if (isset($params['storageid'])) {
58
+            $this->id = 'object::store:' . $params['storageid'];
59
+        } else {
60
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
61
+        }
62
+        //initialize cache with root directory in cache
63
+        if (!$this->is_dir('/')) {
64
+            $this->mkdir('/');
65
+        }
66
+    }
67
+
68
+    public function mkdir($path) {
69
+        $path = $this->normalizePath($path);
70
+
71
+        if ($this->file_exists($path)) {
72
+            return false;
73
+        }
74
+
75
+        $mTime = time();
76
+        $data = [
77
+            'mimetype' => 'httpd/unix-directory',
78
+            'size' => 0,
79
+            'mtime' => $mTime,
80
+            'storage_mtime' => $mTime,
81
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
82
+        ];
83
+        if ($path === '') {
84
+            //create root on the fly
85
+            $data['etag'] = $this->getETag('');
86
+            $this->getCache()->put('', $data);
87
+            return true;
88
+        } else {
89
+            // if parent does not exist, create it
90
+            $parent = $this->normalizePath(dirname($path));
91
+            $parentType = $this->filetype($parent);
92
+            if ($parentType === false) {
93
+                if (!$this->mkdir($parent)) {
94
+                    // something went wrong
95
+                    return false;
96
+                }
97
+            } else if ($parentType === 'file') {
98
+                // parent is a file
99
+                return false;
100
+            }
101
+            // finally create the new dir
102
+            $mTime = time(); // update mtime
103
+            $data['mtime'] = $mTime;
104
+            $data['storage_mtime'] = $mTime;
105
+            $data['etag'] = $this->getETag($path);
106
+            $this->getCache()->put($path, $data);
107
+            return true;
108
+        }
109
+    }
110
+
111
+    /**
112
+     * @param string $path
113
+     * @return string
114
+     */
115
+    private function normalizePath($path) {
116
+        $path = trim($path, '/');
117
+        //FIXME why do we sometimes get a path like 'files//username'?
118
+        $path = str_replace('//', '/', $path);
119
+
120
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
121
+        if (!$path || $path === '.') {
122
+            $path = '';
123
+        }
124
+
125
+        return $path;
126
+    }
127
+
128
+    /**
129
+     * Object Stores use a NoopScanner because metadata is directly stored in
130
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
131
+     *
132
+     * @param string $path
133
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
134
+     * @return \OC\Files\ObjectStore\NoopScanner
135
+     */
136
+    public function getScanner($path = '', $storage = null) {
137
+        if (!$storage) {
138
+            $storage = $this;
139
+        }
140
+        if (!isset($this->scanner)) {
141
+            $this->scanner = new NoopScanner($storage);
142
+        }
143
+        return $this->scanner;
144
+    }
145
+
146
+    public function getId() {
147
+        return $this->id;
148
+    }
149
+
150
+    public function rmdir($path) {
151
+        $path = $this->normalizePath($path);
152
+
153
+        if (!$this->is_dir($path)) {
154
+            return false;
155
+        }
156
+
157
+        $this->rmObjects($path);
158
+
159
+        $this->getCache()->remove($path);
160
+
161
+        return true;
162
+    }
163
+
164
+    private function rmObjects($path) {
165
+        $children = $this->getCache()->getFolderContents($path);
166
+        foreach ($children as $child) {
167
+            if ($child['mimetype'] === 'httpd/unix-directory') {
168
+                $this->rmObjects($child['path']);
169
+            } else {
170
+                $this->unlink($child['path']);
171
+            }
172
+        }
173
+    }
174
+
175
+    public function unlink($path) {
176
+        $path = $this->normalizePath($path);
177
+        $stat = $this->stat($path);
178
+
179
+        if ($stat && isset($stat['fileid'])) {
180
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
181
+                return $this->rmdir($path);
182
+            }
183
+            try {
184
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
185
+            } catch (\Exception $ex) {
186
+                if ($ex->getCode() !== 404) {
187
+                    \OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
188
+                    return false;
189
+                } else {
190
+                    //removing from cache is ok as it does not exist in the objectstore anyway
191
+                }
192
+            }
193
+            $this->getCache()->remove($path);
194
+            return true;
195
+        }
196
+        return false;
197
+    }
198
+
199
+    public function stat($path) {
200
+        $path = $this->normalizePath($path);
201
+        $cacheEntry = $this->getCache()->get($path);
202
+        if ($cacheEntry instanceof CacheEntry) {
203
+            return $cacheEntry->getData();
204
+        } else {
205
+            return false;
206
+        }
207
+    }
208
+
209
+    /**
210
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
211
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
212
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
213
+     *
214
+     * @param int $fileId the fileid
215
+     * @return null|string the unified resource name used to identify the object
216
+     */
217
+    protected function getURN($fileId) {
218
+        if (is_numeric($fileId)) {
219
+            return 'urn:oid:' . $fileId;
220
+        }
221
+        return null;
222
+    }
223
+
224
+    public function opendir($path) {
225
+        $path = $this->normalizePath($path);
226
+
227
+        try {
228
+            $files = array();
229
+            $folderContents = $this->getCache()->getFolderContents($path);
230
+            foreach ($folderContents as $file) {
231
+                $files[] = $file['name'];
232
+            }
233
+
234
+            return IteratorDirectory::wrap($files);
235
+        } catch (\Exception $e) {
236
+            \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
237
+            return false;
238
+        }
239
+    }
240
+
241
+    public function filetype($path) {
242
+        $path = $this->normalizePath($path);
243
+        $stat = $this->stat($path);
244
+        if ($stat) {
245
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
246
+                return 'dir';
247
+            }
248
+            return 'file';
249
+        } else {
250
+            return false;
251
+        }
252
+    }
253
+
254
+    public function fopen($path, $mode) {
255
+        $path = $this->normalizePath($path);
256
+
257
+        switch ($mode) {
258
+            case 'r':
259
+            case 'rb':
260
+                $stat = $this->stat($path);
261
+                if (is_array($stat)) {
262
+                    try {
263
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
264
+                    } catch (\Exception $ex) {
265
+                        \OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
266
+                        return false;
267
+                    }
268
+                } else {
269
+                    return false;
270
+                }
271
+            case 'w':
272
+            case 'wb':
273
+            case 'a':
274
+            case 'ab':
275
+            case 'r+':
276
+            case 'w+':
277
+            case 'wb+':
278
+            case 'a+':
279
+            case 'x':
280
+            case 'x+':
281
+            case 'c':
282
+            case 'c+':
283
+                if (strrpos($path, '.') !== false) {
284
+                    $ext = substr($path, strrpos($path, '.'));
285
+                } else {
286
+                    $ext = '';
287
+                }
288
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
289
+                \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
290
+                if ($this->file_exists($path)) {
291
+                    $source = $this->fopen($path, 'r');
292
+                    file_put_contents($tmpFile, $source);
293
+                }
294
+                self::$tmpFiles[$tmpFile] = $path;
295
+
296
+                return fopen('close://' . $tmpFile, $mode);
297
+        }
298
+        return false;
299
+    }
300
+
301
+    public function file_exists($path) {
302
+        $path = $this->normalizePath($path);
303
+        return (bool)$this->stat($path);
304
+    }
305
+
306
+    public function rename($source, $target) {
307
+        $source = $this->normalizePath($source);
308
+        $target = $this->normalizePath($target);
309
+        $this->remove($target);
310
+        $this->getCache()->move($source, $target);
311
+        $this->touch(dirname($target));
312
+        return true;
313
+    }
314
+
315
+    public function getMimeType($path) {
316
+        $path = $this->normalizePath($path);
317
+        $stat = $this->stat($path);
318
+        if (is_array($stat)) {
319
+            return $stat['mimetype'];
320
+        } else {
321
+            return false;
322
+        }
323
+    }
324
+
325
+    public function touch($path, $mtime = null) {
326
+        if (is_null($mtime)) {
327
+            $mtime = time();
328
+        }
329
+
330
+        $path = $this->normalizePath($path);
331
+        $dirName = dirname($path);
332
+        $parentExists = $this->is_dir($dirName);
333
+        if (!$parentExists) {
334
+            return false;
335
+        }
336
+
337
+        $stat = $this->stat($path);
338
+        if (is_array($stat)) {
339
+            // update existing mtime in db
340
+            $stat['mtime'] = $mtime;
341
+            $this->getCache()->update($stat['fileid'], $stat);
342
+        } else {
343
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
344
+            // create new file
345
+            $stat = array(
346
+                'etag' => $this->getETag($path),
347
+                'mimetype' => $mimeType,
348
+                'size' => 0,
349
+                'mtime' => $mtime,
350
+                'storage_mtime' => $mtime,
351
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
352
+            );
353
+            $fileId = $this->getCache()->put($path, $stat);
354
+            try {
355
+                //read an empty file from memory
356
+                $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
357
+            } catch (\Exception $ex) {
358
+                $this->getCache()->remove($path);
359
+                \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
360
+                return false;
361
+            }
362
+        }
363
+        return true;
364
+    }
365
+
366
+    public function writeBack($tmpFile) {
367
+        if (!isset(self::$tmpFiles[$tmpFile])) {
368
+            return;
369
+        }
370
+
371
+        $path = self::$tmpFiles[$tmpFile];
372
+        $stat = $this->stat($path);
373
+        if (empty($stat)) {
374
+            // create new file
375
+            $stat = array(
376
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
377
+            );
378
+        }
379
+        // update stat with new data
380
+        $mTime = time();
381
+        $stat['size'] = filesize($tmpFile);
382
+        $stat['mtime'] = $mTime;
383
+        $stat['storage_mtime'] = $mTime;
384
+        $stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
385
+        $stat['etag'] = $this->getETag($path);
386
+
387
+        $fileId = $this->getCache()->put($path, $stat);
388
+        try {
389
+            //upload to object storage
390
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
391
+        } catch (\Exception $ex) {
392
+            $this->getCache()->remove($path);
393
+            \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
394
+            throw $ex; // make this bubble up
395
+        }
396
+    }
397
+
398
+    /**
399
+     * external changes are not supported, exclusive access to the object storage is assumed
400
+     *
401
+     * @param string $path
402
+     * @param int $time
403
+     * @return false
404
+     */
405
+    public function hasUpdated($path, $time) {
406
+        return false;
407
+    }
408 408
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -55,9 +55,9 @@  discard block
 block discarded – undo
55 55
 			throw new \Exception('missing IObjectStore instance');
56 56
 		}
57 57
 		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
58
+			$this->id = 'object::store:'.$params['storageid'];
59 59
 		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
60
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
61 61
 		}
62 62
 		//initialize cache with root directory in cache
63 63
 		if (!$this->is_dir('/')) {
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
 				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
185 185
 			} catch (\Exception $ex) {
186 186
 				if ($ex->getCode() !== 404) {
187
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
187
+					\OCP\Util::writeLog('objectstore', 'Could not delete object: '.$ex->getMessage(), \OCP\Util::ERROR);
188 188
 					return false;
189 189
 				} else {
190 190
 					//removing from cache is ok as it does not exist in the objectstore anyway
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 	 */
217 217
 	protected function getURN($fileId) {
218 218
 		if (is_numeric($fileId)) {
219
-			return 'urn:oid:' . $fileId;
219
+			return 'urn:oid:'.$fileId;
220 220
 		}
221 221
 		return null;
222 222
 	}
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 					try {
263 263
 						return $this->objectStore->readObject($this->getURN($stat['fileid']));
264 264
 					} catch (\Exception $ex) {
265
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
265
+						\OCP\Util::writeLog('objectstore', 'Could not get object: '.$ex->getMessage(), \OCP\Util::ERROR);
266 266
 						return false;
267 267
 					}
268 268
 				} else {
@@ -293,14 +293,14 @@  discard block
 block discarded – undo
293 293
 				}
294 294
 				self::$tmpFiles[$tmpFile] = $path;
295 295
 
296
-				return fopen('close://' . $tmpFile, $mode);
296
+				return fopen('close://'.$tmpFile, $mode);
297 297
 		}
298 298
 		return false;
299 299
 	}
300 300
 
301 301
 	public function file_exists($path) {
302 302
 		$path = $this->normalizePath($path);
303
-		return (bool)$this->stat($path);
303
+		return (bool) $this->stat($path);
304 304
 	}
305 305
 
306 306
 	public function rename($source, $target) {
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
 				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
357 357
 			} catch (\Exception $ex) {
358 358
 				$this->getCache()->remove($path);
359
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
359
+				\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
360 360
 				return false;
361 361
 			}
362 362
 		}
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
391 391
 		} catch (\Exception $ex) {
392 392
 			$this->getCache()->remove($path);
393
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
393
+			\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
394 394
 			throw $ex; // make this bubble up
395 395
 		}
396 396
 	}
Please login to merge, or discard this patch.
lib/private/Files/Storage/Flysystem.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -54,6 +54,9 @@
 block discarded – undo
54 54
 		$this->flysystem->addPlugin(new GetWithMetadata());
55 55
 	}
56 56
 
57
+	/**
58
+	 * @param string $path
59
+	 */
57 60
 	protected function buildPath($path) {
58 61
 		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
59 62
 		return ltrim($fullPath, '/');
Please login to merge, or discard this patch.
Indentation   +201 added lines, -201 removed lines patch added patch discarded remove patch
@@ -35,223 +35,223 @@
 block discarded – undo
35 35
  * To use: subclass and call $this->buildFlysystem with the flysystem adapter of choice
36 36
  */
37 37
 abstract class Flysystem extends Common {
38
-	/**
39
-	 * @var Filesystem
40
-	 */
41
-	protected $flysystem;
38
+    /**
39
+     * @var Filesystem
40
+     */
41
+    protected $flysystem;
42 42
 
43
-	/**
44
-	 * @var string
45
-	 */
46
-	protected $root = '';
43
+    /**
44
+     * @var string
45
+     */
46
+    protected $root = '';
47 47
 
48
-	/**
49
-	 * Initialize the storage backend with a flyssytem adapter
50
-	 *
51
-	 * @param \League\Flysystem\AdapterInterface $adapter
52
-	 */
53
-	protected function buildFlySystem(AdapterInterface $adapter) {
54
-		$this->flysystem = new Filesystem($adapter);
55
-		$this->flysystem->addPlugin(new GetWithMetadata());
56
-	}
48
+    /**
49
+     * Initialize the storage backend with a flyssytem adapter
50
+     *
51
+     * @param \League\Flysystem\AdapterInterface $adapter
52
+     */
53
+    protected function buildFlySystem(AdapterInterface $adapter) {
54
+        $this->flysystem = new Filesystem($adapter);
55
+        $this->flysystem->addPlugin(new GetWithMetadata());
56
+    }
57 57
 
58
-	protected function buildPath($path) {
59
-		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
60
-		return ltrim($fullPath, '/');
61
-	}
58
+    protected function buildPath($path) {
59
+        $fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
60
+        return ltrim($fullPath, '/');
61
+    }
62 62
 
63
-	/**
64
-	 * {@inheritdoc}
65
-	 */
66
-	public function file_get_contents($path) {
67
-		return $this->flysystem->read($this->buildPath($path));
68
-	}
63
+    /**
64
+     * {@inheritdoc}
65
+     */
66
+    public function file_get_contents($path) {
67
+        return $this->flysystem->read($this->buildPath($path));
68
+    }
69 69
 
70
-	/**
71
-	 * {@inheritdoc}
72
-	 */
73
-	public function file_put_contents($path, $data) {
74
-		return $this->flysystem->put($this->buildPath($path), $data);
75
-	}
70
+    /**
71
+     * {@inheritdoc}
72
+     */
73
+    public function file_put_contents($path, $data) {
74
+        return $this->flysystem->put($this->buildPath($path), $data);
75
+    }
76 76
 
77
-	/**
78
-	 * {@inheritdoc}
79
-	 */
80
-	public function file_exists($path) {
81
-		return $this->flysystem->has($this->buildPath($path));
82
-	}
77
+    /**
78
+     * {@inheritdoc}
79
+     */
80
+    public function file_exists($path) {
81
+        return $this->flysystem->has($this->buildPath($path));
82
+    }
83 83
 
84
-	/**
85
-	 * {@inheritdoc}
86
-	 */
87
-	public function unlink($path) {
88
-		if ($this->is_dir($path)) {
89
-			return $this->rmdir($path);
90
-		}
91
-		try {
92
-			return $this->flysystem->delete($this->buildPath($path));
93
-		} catch (FileNotFoundException $e) {
94
-			return false;
95
-		}
96
-	}
84
+    /**
85
+     * {@inheritdoc}
86
+     */
87
+    public function unlink($path) {
88
+        if ($this->is_dir($path)) {
89
+            return $this->rmdir($path);
90
+        }
91
+        try {
92
+            return $this->flysystem->delete($this->buildPath($path));
93
+        } catch (FileNotFoundException $e) {
94
+            return false;
95
+        }
96
+    }
97 97
 
98
-	/**
99
-	 * {@inheritdoc}
100
-	 */
101
-	public function rename($source, $target) {
102
-		if ($this->file_exists($target)) {
103
-			$this->unlink($target);
104
-		}
105
-		return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
106
-	}
98
+    /**
99
+     * {@inheritdoc}
100
+     */
101
+    public function rename($source, $target) {
102
+        if ($this->file_exists($target)) {
103
+            $this->unlink($target);
104
+        }
105
+        return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
106
+    }
107 107
 
108
-	/**
109
-	 * {@inheritdoc}
110
-	 */
111
-	public function copy($source, $target) {
112
-		if ($this->file_exists($target)) {
113
-			$this->unlink($target);
114
-		}
115
-		return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
116
-	}
108
+    /**
109
+     * {@inheritdoc}
110
+     */
111
+    public function copy($source, $target) {
112
+        if ($this->file_exists($target)) {
113
+            $this->unlink($target);
114
+        }
115
+        return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
116
+    }
117 117
 
118
-	/**
119
-	 * {@inheritdoc}
120
-	 */
121
-	public function filesize($path) {
122
-		if ($this->is_dir($path)) {
123
-			return 0;
124
-		} else {
125
-			return $this->flysystem->getSize($this->buildPath($path));
126
-		}
127
-	}
118
+    /**
119
+     * {@inheritdoc}
120
+     */
121
+    public function filesize($path) {
122
+        if ($this->is_dir($path)) {
123
+            return 0;
124
+        } else {
125
+            return $this->flysystem->getSize($this->buildPath($path));
126
+        }
127
+    }
128 128
 
129
-	/**
130
-	 * {@inheritdoc}
131
-	 */
132
-	public function mkdir($path) {
133
-		if ($this->file_exists($path)) {
134
-			return false;
135
-		}
136
-		return $this->flysystem->createDir($this->buildPath($path));
137
-	}
129
+    /**
130
+     * {@inheritdoc}
131
+     */
132
+    public function mkdir($path) {
133
+        if ($this->file_exists($path)) {
134
+            return false;
135
+        }
136
+        return $this->flysystem->createDir($this->buildPath($path));
137
+    }
138 138
 
139
-	/**
140
-	 * {@inheritdoc}
141
-	 */
142
-	public function filemtime($path) {
143
-		return $this->flysystem->getTimestamp($this->buildPath($path));
144
-	}
139
+    /**
140
+     * {@inheritdoc}
141
+     */
142
+    public function filemtime($path) {
143
+        return $this->flysystem->getTimestamp($this->buildPath($path));
144
+    }
145 145
 
146
-	/**
147
-	 * {@inheritdoc}
148
-	 */
149
-	public function rmdir($path) {
150
-		try {
151
-			return @$this->flysystem->deleteDir($this->buildPath($path));
152
-		} catch (FileNotFoundException $e) {
153
-			return false;
154
-		}
155
-	}
146
+    /**
147
+     * {@inheritdoc}
148
+     */
149
+    public function rmdir($path) {
150
+        try {
151
+            return @$this->flysystem->deleteDir($this->buildPath($path));
152
+        } catch (FileNotFoundException $e) {
153
+            return false;
154
+        }
155
+    }
156 156
 
157
-	/**
158
-	 * {@inheritdoc}
159
-	 */
160
-	public function opendir($path) {
161
-		try {
162
-			$content = $this->flysystem->listContents($this->buildPath($path));
163
-		} catch (FileNotFoundException $e) {
164
-			return false;
165
-		}
166
-		$names = array_map(function ($object) {
167
-			return $object['basename'];
168
-		}, $content);
169
-		return IteratorDirectory::wrap($names);
170
-	}
157
+    /**
158
+     * {@inheritdoc}
159
+     */
160
+    public function opendir($path) {
161
+        try {
162
+            $content = $this->flysystem->listContents($this->buildPath($path));
163
+        } catch (FileNotFoundException $e) {
164
+            return false;
165
+        }
166
+        $names = array_map(function ($object) {
167
+            return $object['basename'];
168
+        }, $content);
169
+        return IteratorDirectory::wrap($names);
170
+    }
171 171
 
172
-	/**
173
-	 * {@inheritdoc}
174
-	 */
175
-	public function fopen($path, $mode) {
176
-		$fullPath = $this->buildPath($path);
177
-		$useExisting = true;
178
-		switch ($mode) {
179
-			case 'r':
180
-			case 'rb':
181
-				try {
182
-					return $this->flysystem->readStream($fullPath);
183
-				} catch (FileNotFoundException $e) {
184
-					return false;
185
-				}
186
-			case 'w':
187
-			case 'w+':
188
-			case 'wb':
189
-			case 'wb+':
190
-				$useExisting = false;
191
-			case 'a':
192
-			case 'ab':
193
-			case 'r+':
194
-			case 'a+':
195
-			case 'x':
196
-			case 'x+':
197
-			case 'c':
198
-			case 'c+':
199
-				//emulate these
200
-				if ($useExisting and $this->file_exists($path)) {
201
-					if (!$this->isUpdatable($path)) {
202
-						return false;
203
-					}
204
-					$tmpFile = $this->getCachedFile($path);
205
-				} else {
206
-					if (!$this->isCreatable(dirname($path))) {
207
-						return false;
208
-					}
209
-					$tmpFile = \OCP\Files::tmpFile();
210
-				}
211
-				$source = fopen($tmpFile, $mode);
212
-				return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
213
-					$this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214
-					unlink($tmpFile);
215
-				});
216
-		}
217
-		return false;
218
-	}
172
+    /**
173
+     * {@inheritdoc}
174
+     */
175
+    public function fopen($path, $mode) {
176
+        $fullPath = $this->buildPath($path);
177
+        $useExisting = true;
178
+        switch ($mode) {
179
+            case 'r':
180
+            case 'rb':
181
+                try {
182
+                    return $this->flysystem->readStream($fullPath);
183
+                } catch (FileNotFoundException $e) {
184
+                    return false;
185
+                }
186
+            case 'w':
187
+            case 'w+':
188
+            case 'wb':
189
+            case 'wb+':
190
+                $useExisting = false;
191
+            case 'a':
192
+            case 'ab':
193
+            case 'r+':
194
+            case 'a+':
195
+            case 'x':
196
+            case 'x+':
197
+            case 'c':
198
+            case 'c+':
199
+                //emulate these
200
+                if ($useExisting and $this->file_exists($path)) {
201
+                    if (!$this->isUpdatable($path)) {
202
+                        return false;
203
+                    }
204
+                    $tmpFile = $this->getCachedFile($path);
205
+                } else {
206
+                    if (!$this->isCreatable(dirname($path))) {
207
+                        return false;
208
+                    }
209
+                    $tmpFile = \OCP\Files::tmpFile();
210
+                }
211
+                $source = fopen($tmpFile, $mode);
212
+                return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
213
+                    $this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214
+                    unlink($tmpFile);
215
+                });
216
+        }
217
+        return false;
218
+    }
219 219
 
220
-	/**
221
-	 * {@inheritdoc}
222
-	 */
223
-	public function touch($path, $mtime = null) {
224
-		if ($this->file_exists($path)) {
225
-			return false;
226
-		} else {
227
-			$this->file_put_contents($path, '');
228
-			return true;
229
-		}
230
-	}
220
+    /**
221
+     * {@inheritdoc}
222
+     */
223
+    public function touch($path, $mtime = null) {
224
+        if ($this->file_exists($path)) {
225
+            return false;
226
+        } else {
227
+            $this->file_put_contents($path, '');
228
+            return true;
229
+        }
230
+    }
231 231
 
232
-	/**
233
-	 * {@inheritdoc}
234
-	 */
235
-	public function stat($path) {
236
-		$info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
237
-		return [
238
-			'mtime' => $info['timestamp'],
239
-			'size' => $info['size']
240
-		];
241
-	}
232
+    /**
233
+     * {@inheritdoc}
234
+     */
235
+    public function stat($path) {
236
+        $info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
237
+        return [
238
+            'mtime' => $info['timestamp'],
239
+            'size' => $info['size']
240
+        ];
241
+    }
242 242
 
243
-	/**
244
-	 * {@inheritdoc}
245
-	 */
246
-	public function filetype($path) {
247
-		if ($path === '' or $path === '/' or $path === '.') {
248
-			return 'dir';
249
-		}
250
-		try {
251
-			$info = $this->flysystem->getMetadata($this->buildPath($path));
252
-		} catch (FileNotFoundException $e) {
253
-			return false;
254
-		}
255
-		return $info['type'];
256
-	}
243
+    /**
244
+     * {@inheritdoc}
245
+     */
246
+    public function filetype($path) {
247
+        if ($path === '' or $path === '/' or $path === '.') {
248
+            return 'dir';
249
+        }
250
+        try {
251
+            $info = $this->flysystem->getMetadata($this->buildPath($path));
252
+        } catch (FileNotFoundException $e) {
253
+            return false;
254
+        }
255
+        return $info['type'];
256
+    }
257 257
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -56,7 +56,7 @@  discard block
 block discarded – undo
56 56
 	}
57 57
 
58 58
 	protected function buildPath($path) {
59
-		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
59
+		$fullPath = \OC\Files\Filesystem::normalizePath($this->root.'/'.$path);
60 60
 		return ltrim($fullPath, '/');
61 61
 	}
62 62
 
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 		} catch (FileNotFoundException $e) {
164 164
 			return false;
165 165
 		}
166
-		$names = array_map(function ($object) {
166
+		$names = array_map(function($object) {
167 167
 			return $object['basename'];
168 168
 		}, $content);
169 169
 		return IteratorDirectory::wrap($names);
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
 					$tmpFile = \OCP\Files::tmpFile();
210 210
 				}
211 211
 				$source = fopen($tmpFile, $mode);
212
-				return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
212
+				return CallbackWrapper::wrap($source, null, null, function() use ($tmpFile, $fullPath) {
213 213
 					$this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214 214
 					unlink($tmpFile);
215 215
 				});
Please login to merge, or discard this patch.
lib/private/Files/Storage/Storage.php 2 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -99,6 +99,7 @@  discard block
 block discarded – undo
99 99
 	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
100 100
 	 * @param \OCP\Lock\ILockingProvider $provider
101 101
 	 * @throws \OCP\Lock\LockedException
102
+	 * @return void
102 103
 	 */
103 104
 	public function acquireLock($path, $type, ILockingProvider $provider);
104 105
 
@@ -106,6 +107,7 @@  discard block
 block discarded – undo
106 107
 	 * @param string $path The path of the file to release the lock for
107 108
 	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
108 109
 	 * @param \OCP\Lock\ILockingProvider $provider
110
+	 * @return void
109 111
 	 */
110 112
 	public function releaseLock($path, $type, ILockingProvider $provider);
111 113
 
@@ -114,6 +116,7 @@  discard block
 block discarded – undo
114 116
 	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
115 117
 	 * @param \OCP\Lock\ILockingProvider $provider
116 118
 	 * @throws \OCP\Lock\LockedException
119
+	 * @return void
117 120
 	 */
118 121
 	public function changeLock($path, $type, ILockingProvider $provider);
119 122
 }
Please login to merge, or discard this patch.
Indentation   +74 added lines, -74 removed lines patch added patch discarded remove patch
@@ -32,89 +32,89 @@
 block discarded – undo
32 32
  */
33 33
 interface Storage extends \OCP\Files\Storage {
34 34
 
35
-	/**
36
-	 * get a cache instance for the storage
37
-	 *
38
-	 * @param string $path
39
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
40
-	 * @return \OC\Files\Cache\Cache
41
-	 */
42
-	public function getCache($path = '', $storage = null);
35
+    /**
36
+     * get a cache instance for the storage
37
+     *
38
+     * @param string $path
39
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
40
+     * @return \OC\Files\Cache\Cache
41
+     */
42
+    public function getCache($path = '', $storage = null);
43 43
 
44
-	/**
45
-	 * get a scanner instance for the storage
46
-	 *
47
-	 * @param string $path
48
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
49
-	 * @return \OC\Files\Cache\Scanner
50
-	 */
51
-	public function getScanner($path = '', $storage = null);
44
+    /**
45
+     * get a scanner instance for the storage
46
+     *
47
+     * @param string $path
48
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
49
+     * @return \OC\Files\Cache\Scanner
50
+     */
51
+    public function getScanner($path = '', $storage = null);
52 52
 
53 53
 
54
-	/**
55
-	 * get the user id of the owner of a file or folder
56
-	 *
57
-	 * @param string $path
58
-	 * @return string
59
-	 */
60
-	public function getOwner($path);
54
+    /**
55
+     * get the user id of the owner of a file or folder
56
+     *
57
+     * @param string $path
58
+     * @return string
59
+     */
60
+    public function getOwner($path);
61 61
 
62
-	/**
63
-	 * get a watcher instance for the cache
64
-	 *
65
-	 * @param string $path
66
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
67
-	 * @return \OC\Files\Cache\Watcher
68
-	 */
69
-	public function getWatcher($path = '', $storage = null);
62
+    /**
63
+     * get a watcher instance for the cache
64
+     *
65
+     * @param string $path
66
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
67
+     * @return \OC\Files\Cache\Watcher
68
+     */
69
+    public function getWatcher($path = '', $storage = null);
70 70
 
71
-	/**
72
-	 * get a propagator instance for the cache
73
-	 *
74
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
75
-	 * @return \OC\Files\Cache\Propagator
76
-	 */
77
-	public function getPropagator($storage = null);
71
+    /**
72
+     * get a propagator instance for the cache
73
+     *
74
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
75
+     * @return \OC\Files\Cache\Propagator
76
+     */
77
+    public function getPropagator($storage = null);
78 78
 
79
-	/**
80
-	 * get a updater instance for the cache
81
-	 *
82
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
83
-	 * @return \OC\Files\Cache\Updater
84
-	 */
85
-	public function getUpdater($storage = null);
79
+    /**
80
+     * get a updater instance for the cache
81
+     *
82
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
83
+     * @return \OC\Files\Cache\Updater
84
+     */
85
+    public function getUpdater($storage = null);
86 86
 
87
-	/**
88
-	 * @return \OC\Files\Cache\Storage
89
-	 */
90
-	public function getStorageCache();
87
+    /**
88
+     * @return \OC\Files\Cache\Storage
89
+     */
90
+    public function getStorageCache();
91 91
 
92
-	/**
93
-	 * @param string $path
94
-	 * @return array
95
-	 */
96
-	public function getMetaData($path);
92
+    /**
93
+     * @param string $path
94
+     * @return array
95
+     */
96
+    public function getMetaData($path);
97 97
 
98
-	/**
99
-	 * @param string $path The path of the file to acquire the lock for
100
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
101
-	 * @param \OCP\Lock\ILockingProvider $provider
102
-	 * @throws \OCP\Lock\LockedException
103
-	 */
104
-	public function acquireLock($path, $type, ILockingProvider $provider);
98
+    /**
99
+     * @param string $path The path of the file to acquire the lock for
100
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
101
+     * @param \OCP\Lock\ILockingProvider $provider
102
+     * @throws \OCP\Lock\LockedException
103
+     */
104
+    public function acquireLock($path, $type, ILockingProvider $provider);
105 105
 
106
-	/**
107
-	 * @param string $path The path of the file to release the lock for
108
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
109
-	 * @param \OCP\Lock\ILockingProvider $provider
110
-	 */
111
-	public function releaseLock($path, $type, ILockingProvider $provider);
106
+    /**
107
+     * @param string $path The path of the file to release the lock for
108
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
109
+     * @param \OCP\Lock\ILockingProvider $provider
110
+     */
111
+    public function releaseLock($path, $type, ILockingProvider $provider);
112 112
 
113
-	/**
114
-	 * @param string $path The path of the file to change the lock for
115
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
116
-	 * @param \OCP\Lock\ILockingProvider $provider
117
-	 * @throws \OCP\Lock\LockedException
118
-	 */
119
-	public function changeLock($path, $type, ILockingProvider $provider);
113
+    /**
114
+     * @param string $path The path of the file to change the lock for
115
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
116
+     * @param \OCP\Lock\ILockingProvider $provider
117
+     * @throws \OCP\Lock\LockedException
118
+     */
119
+    public function changeLock($path, $type, ILockingProvider $provider);
120 120
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Encryption.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -982,7 +982,7 @@
 block discarded – undo
982 982
 	/**
983 983
 	 * check if path points to a files version
984 984
 	 *
985
-	 * @param $path
985
+	 * @param string $path
986 986
 	 * @return bool
987 987
 	 */
988 988
 	protected function isVersion($path) {
Please login to merge, or discard this patch.
Indentation   +944 added lines, -944 removed lines patch added patch discarded remove patch
@@ -46,949 +46,949 @@
 block discarded – undo
46 46
 
47 47
 class Encryption extends Wrapper {
48 48
 
49
-	use LocalTempFileTrait;
50
-
51
-	/** @var string */
52
-	private $mountPoint;
53
-
54
-	/** @var \OC\Encryption\Util */
55
-	private $util;
56
-
57
-	/** @var \OCP\Encryption\IManager */
58
-	private $encryptionManager;
59
-
60
-	/** @var \OCP\ILogger */
61
-	private $logger;
62
-
63
-	/** @var string */
64
-	private $uid;
65
-
66
-	/** @var array */
67
-	protected $unencryptedSize;
68
-
69
-	/** @var \OCP\Encryption\IFile */
70
-	private $fileHelper;
71
-
72
-	/** @var IMountPoint */
73
-	private $mount;
74
-
75
-	/** @var IStorage */
76
-	private $keyStorage;
77
-
78
-	/** @var Update */
79
-	private $update;
80
-
81
-	/** @var Manager */
82
-	private $mountManager;
83
-
84
-	/** @var array remember for which path we execute the repair step to avoid recursions */
85
-	private $fixUnencryptedSizeOf = array();
86
-
87
-	/** @var  ArrayCache */
88
-	private $arrayCache;
89
-
90
-	/**
91
-	 * @param array $parameters
92
-	 * @param IManager $encryptionManager
93
-	 * @param Util $util
94
-	 * @param ILogger $logger
95
-	 * @param IFile $fileHelper
96
-	 * @param string $uid
97
-	 * @param IStorage $keyStorage
98
-	 * @param Update $update
99
-	 * @param Manager $mountManager
100
-	 * @param ArrayCache $arrayCache
101
-	 */
102
-	public function __construct(
103
-			$parameters,
104
-			IManager $encryptionManager = null,
105
-			Util $util = null,
106
-			ILogger $logger = null,
107
-			IFile $fileHelper = null,
108
-			$uid = null,
109
-			IStorage $keyStorage = null,
110
-			Update $update = null,
111
-			Manager $mountManager = null,
112
-			ArrayCache $arrayCache = null
113
-		) {
114
-
115
-		$this->mountPoint = $parameters['mountPoint'];
116
-		$this->mount = $parameters['mount'];
117
-		$this->encryptionManager = $encryptionManager;
118
-		$this->util = $util;
119
-		$this->logger = $logger;
120
-		$this->uid = $uid;
121
-		$this->fileHelper = $fileHelper;
122
-		$this->keyStorage = $keyStorage;
123
-		$this->unencryptedSize = array();
124
-		$this->update = $update;
125
-		$this->mountManager = $mountManager;
126
-		$this->arrayCache = $arrayCache;
127
-		parent::__construct($parameters);
128
-	}
129
-
130
-	/**
131
-	 * see http://php.net/manual/en/function.filesize.php
132
-	 * The result for filesize when called on a folder is required to be 0
133
-	 *
134
-	 * @param string $path
135
-	 * @return int
136
-	 */
137
-	public function filesize($path) {
138
-		$fullPath = $this->getFullPath($path);
139
-
140
-		/** @var CacheEntry $info */
141
-		$info = $this->getCache()->get($path);
142
-		if (isset($this->unencryptedSize[$fullPath])) {
143
-			$size = $this->unencryptedSize[$fullPath];
144
-			// update file cache
145
-			if ($info instanceof ICacheEntry) {
146
-				$info = $info->getData();
147
-				$info['encrypted'] = $info['encryptedVersion'];
148
-			} else {
149
-				if (!is_array($info)) {
150
-					$info = [];
151
-				}
152
-				$info['encrypted'] = true;
153
-			}
154
-
155
-			$info['size'] = $size;
156
-			$this->getCache()->put($path, $info);
157
-
158
-			return $size;
159
-		}
160
-
161
-		if (isset($info['fileid']) && $info['encrypted']) {
162
-			return $this->verifyUnencryptedSize($path, $info['size']);
163
-		}
164
-
165
-		return $this->storage->filesize($path);
166
-	}
167
-
168
-	/**
169
-	 * @param string $path
170
-	 * @return array
171
-	 */
172
-	public function getMetaData($path) {
173
-		$data = $this->storage->getMetaData($path);
174
-		if (is_null($data)) {
175
-			return null;
176
-		}
177
-		$fullPath = $this->getFullPath($path);
178
-		$info = $this->getCache()->get($path);
179
-
180
-		if (isset($this->unencryptedSize[$fullPath])) {
181
-			$data['encrypted'] = true;
182
-			$data['size'] = $this->unencryptedSize[$fullPath];
183
-		} else {
184
-			if (isset($info['fileid']) && $info['encrypted']) {
185
-				$data['size'] = $this->verifyUnencryptedSize($path, $info['size']);
186
-				$data['encrypted'] = true;
187
-			}
188
-		}
189
-
190
-		if (isset($info['encryptedVersion']) && $info['encryptedVersion'] > 1) {
191
-			$data['encryptedVersion'] = $info['encryptedVersion'];
192
-		}
193
-
194
-		return $data;
195
-	}
196
-
197
-	/**
198
-	 * see http://php.net/manual/en/function.file_get_contents.php
199
-	 *
200
-	 * @param string $path
201
-	 * @return string
202
-	 */
203
-	public function file_get_contents($path) {
204
-
205
-		$encryptionModule = $this->getEncryptionModule($path);
206
-
207
-		if ($encryptionModule) {
208
-			$handle = $this->fopen($path, "r");
209
-			if (!$handle) {
210
-				return false;
211
-			}
212
-			$data = stream_get_contents($handle);
213
-			fclose($handle);
214
-			return $data;
215
-		}
216
-		return $this->storage->file_get_contents($path);
217
-	}
218
-
219
-	/**
220
-	 * see http://php.net/manual/en/function.file_put_contents.php
221
-	 *
222
-	 * @param string $path
223
-	 * @param string $data
224
-	 * @return bool
225
-	 */
226
-	public function file_put_contents($path, $data) {
227
-		// file put content will always be translated to a stream write
228
-		$handle = $this->fopen($path, 'w');
229
-		if (is_resource($handle)) {
230
-			$written = fwrite($handle, $data);
231
-			fclose($handle);
232
-			return $written;
233
-		}
234
-
235
-		return false;
236
-	}
237
-
238
-	/**
239
-	 * see http://php.net/manual/en/function.unlink.php
240
-	 *
241
-	 * @param string $path
242
-	 * @return bool
243
-	 */
244
-	public function unlink($path) {
245
-		$fullPath = $this->getFullPath($path);
246
-		if ($this->util->isExcluded($fullPath)) {
247
-			return $this->storage->unlink($path);
248
-		}
249
-
250
-		$encryptionModule = $this->getEncryptionModule($path);
251
-		if ($encryptionModule) {
252
-			$this->keyStorage->deleteAllFileKeys($this->getFullPath($path));
253
-		}
254
-
255
-		return $this->storage->unlink($path);
256
-	}
257
-
258
-	/**
259
-	 * see http://php.net/manual/en/function.rename.php
260
-	 *
261
-	 * @param string $path1
262
-	 * @param string $path2
263
-	 * @return bool
264
-	 */
265
-	public function rename($path1, $path2) {
266
-
267
-		$result = $this->storage->rename($path1, $path2);
268
-
269
-		if ($result &&
270
-			// versions always use the keys from the original file, so we can skip
271
-			// this step for versions
272
-			$this->isVersion($path2) === false &&
273
-			$this->encryptionManager->isEnabled()) {
274
-			$source = $this->getFullPath($path1);
275
-			if (!$this->util->isExcluded($source)) {
276
-				$target = $this->getFullPath($path2);
277
-				if (isset($this->unencryptedSize[$source])) {
278
-					$this->unencryptedSize[$target] = $this->unencryptedSize[$source];
279
-				}
280
-				$this->keyStorage->renameKeys($source, $target);
281
-				$module = $this->getEncryptionModule($path2);
282
-				if ($module) {
283
-					$module->update($target, $this->uid, []);
284
-				}
285
-			}
286
-		}
287
-
288
-		return $result;
289
-	}
290
-
291
-	/**
292
-	 * see http://php.net/manual/en/function.rmdir.php
293
-	 *
294
-	 * @param string $path
295
-	 * @return bool
296
-	 */
297
-	public function rmdir($path) {
298
-		$result = $this->storage->rmdir($path);
299
-		$fullPath = $this->getFullPath($path);
300
-		if ($result &&
301
-			$this->util->isExcluded($fullPath) === false &&
302
-			$this->encryptionManager->isEnabled()
303
-		) {
304
-			$this->keyStorage->deleteAllFileKeys($fullPath);
305
-		}
306
-
307
-		return $result;
308
-	}
309
-
310
-	/**
311
-	 * check if a file can be read
312
-	 *
313
-	 * @param string $path
314
-	 * @return bool
315
-	 */
316
-	public function isReadable($path) {
317
-
318
-		$isReadable = true;
319
-
320
-		$metaData = $this->getMetaData($path);
321
-		if (
322
-			!$this->is_dir($path) &&
323
-			isset($metaData['encrypted']) &&
324
-			$metaData['encrypted'] === true
325
-		) {
326
-			$fullPath = $this->getFullPath($path);
327
-			$module = $this->getEncryptionModule($path);
328
-			$isReadable = $module->isReadable($fullPath, $this->uid);
329
-		}
330
-
331
-		return $this->storage->isReadable($path) && $isReadable;
332
-	}
333
-
334
-	/**
335
-	 * see http://php.net/manual/en/function.copy.php
336
-	 *
337
-	 * @param string $path1
338
-	 * @param string $path2
339
-	 * @return bool
340
-	 */
341
-	public function copy($path1, $path2) {
342
-
343
-		$source = $this->getFullPath($path1);
344
-
345
-		if ($this->util->isExcluded($source)) {
346
-			return $this->storage->copy($path1, $path2);
347
-		}
348
-
349
-		// need to stream copy file by file in case we copy between a encrypted
350
-		// and a unencrypted storage
351
-		$this->unlink($path2);
352
-		$result = $this->copyFromStorage($this, $path1, $path2);
353
-
354
-		return $result;
355
-	}
356
-
357
-	/**
358
-	 * see http://php.net/manual/en/function.fopen.php
359
-	 *
360
-	 * @param string $path
361
-	 * @param string $mode
362
-	 * @return resource|bool
363
-	 * @throws GenericEncryptionException
364
-	 * @throws ModuleDoesNotExistsException
365
-	 */
366
-	public function fopen($path, $mode) {
367
-
368
-		// check if the file is stored in the array cache, this means that we
369
-		// copy a file over to the versions folder, in this case we don't want to
370
-		// decrypt it
371
-		if ($this->arrayCache->hasKey('encryption_copy_version_' . $path)) {
372
-			$this->arrayCache->remove('encryption_copy_version_' . $path);
373
-			return $this->storage->fopen($path, $mode);
374
-		}
375
-
376
-		$encryptionEnabled = $this->encryptionManager->isEnabled();
377
-		$shouldEncrypt = false;
378
-		$encryptionModule = null;
379
-		$header = $this->getHeader($path);
380
-		$signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false;
381
-		$fullPath = $this->getFullPath($path);
382
-		$encryptionModuleId = $this->util->getEncryptionModuleId($header);
383
-
384
-		if ($this->util->isExcluded($fullPath) === false) {
385
-
386
-			$size = $unencryptedSize = 0;
387
-			$realFile = $this->util->stripPartialFileExtension($path);
388
-			$targetExists = $this->file_exists($realFile) || $this->file_exists($path);
389
-			$targetIsEncrypted = false;
390
-			if ($targetExists) {
391
-				// in case the file exists we require the explicit module as
392
-				// specified in the file header - otherwise we need to fail hard to
393
-				// prevent data loss on client side
394
-				if (!empty($encryptionModuleId)) {
395
-					$targetIsEncrypted = true;
396
-					$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
397
-				}
398
-
399
-				if ($this->file_exists($path)) {
400
-					$size = $this->storage->filesize($path);
401
-					$unencryptedSize = $this->filesize($path);
402
-				} else {
403
-					$size = $unencryptedSize = 0;
404
-				}
405
-			}
406
-
407
-			try {
408
-
409
-				if (
410
-					$mode === 'w'
411
-					|| $mode === 'w+'
412
-					|| $mode === 'wb'
413
-					|| $mode === 'wb+'
414
-				) {
415
-					// don't overwrite encrypted files if encryption is not enabled
416
-					if ($targetIsEncrypted && $encryptionEnabled === false) {
417
-						throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled');
418
-					}
419
-					if ($encryptionEnabled) {
420
-						// if $encryptionModuleId is empty, the default module will be used
421
-						$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
422
-						$shouldEncrypt = $encryptionModule->shouldEncrypt($fullPath);
423
-						$signed = true;
424
-					}
425
-				} else {
426
-					$info = $this->getCache()->get($path);
427
-					// only get encryption module if we found one in the header
428
-					// or if file should be encrypted according to the file cache
429
-					if (!empty($encryptionModuleId)) {
430
-						$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
431
-						$shouldEncrypt = true;
432
-					} else if (empty($encryptionModuleId) && $info['encrypted'] === true) {
433
-						// we come from a old installation. No header and/or no module defined
434
-						// but the file is encrypted. In this case we need to use the
435
-						// OC_DEFAULT_MODULE to read the file
436
-						$encryptionModule = $this->encryptionManager->getEncryptionModule('OC_DEFAULT_MODULE');
437
-						$shouldEncrypt = true;
438
-						$targetIsEncrypted = true;
439
-					}
440
-				}
441
-			} catch (ModuleDoesNotExistsException $e) {
442
-				$this->logger->warning('Encryption module "' . $encryptionModuleId .
443
-					'" not found, file will be stored unencrypted (' . $e->getMessage() . ')');
444
-			}
445
-
446
-			// encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt
447
-			if (!$encryptionEnabled || !$this->mount->getOption('encrypt', true)) {
448
-				if (!$targetExists || !$targetIsEncrypted) {
449
-					$shouldEncrypt = false;
450
-				}
451
-			}
452
-
453
-			if ($shouldEncrypt === true && $encryptionModule !== null) {
454
-				$headerSize = $this->getHeaderSize($path);
455
-				$source = $this->storage->fopen($path, $mode);
456
-				if (!is_resource($source)) {
457
-					return false;
458
-				}
459
-				$handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header,
460
-					$this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode,
461
-					$size, $unencryptedSize, $headerSize, $signed);
462
-				return $handle;
463
-			}
464
-
465
-		}
466
-
467
-		return $this->storage->fopen($path, $mode);
468
-	}
469
-
470
-
471
-	/**
472
-	 * perform some plausibility checks if the the unencrypted size is correct.
473
-	 * If not, we calculate the correct unencrypted size and return it
474
-	 *
475
-	 * @param string $path internal path relative to the storage root
476
-	 * @param int $unencryptedSize size of the unencrypted file
477
-	 *
478
-	 * @return int unencrypted size
479
-	 */
480
-	protected function verifyUnencryptedSize($path, $unencryptedSize) {
481
-
482
-		$size = $this->storage->filesize($path);
483
-		$result = $unencryptedSize;
484
-
485
-		if ($unencryptedSize < 0 ||
486
-			($size > 0 && $unencryptedSize === $size)
487
-		) {
488
-			// check if we already calculate the unencrypted size for the
489
-			// given path to avoid recursions
490
-			if (isset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]) === false) {
491
-				$this->fixUnencryptedSizeOf[$this->getFullPath($path)] = true;
492
-				try {
493
-					$result = $this->fixUnencryptedSize($path, $size, $unencryptedSize);
494
-				} catch (\Exception $e) {
495
-					$this->logger->error('Couldn\'t re-calculate unencrypted size for '. $path);
496
-					$this->logger->logException($e);
497
-				}
498
-				unset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]);
499
-			}
500
-		}
501
-
502
-		return $result;
503
-	}
504
-
505
-	/**
506
-	 * calculate the unencrypted size
507
-	 *
508
-	 * @param string $path internal path relative to the storage root
509
-	 * @param int $size size of the physical file
510
-	 * @param int $unencryptedSize size of the unencrypted file
511
-	 *
512
-	 * @return int calculated unencrypted size
513
-	 */
514
-	protected function fixUnencryptedSize($path, $size, $unencryptedSize) {
515
-
516
-		$headerSize = $this->getHeaderSize($path);
517
-		$header = $this->getHeader($path);
518
-		$encryptionModule = $this->getEncryptionModule($path);
519
-
520
-		$stream = $this->storage->fopen($path, 'r');
521
-
522
-		// if we couldn't open the file we return the old unencrypted size
523
-		if (!is_resource($stream)) {
524
-			$this->logger->error('Could not open ' . $path . '. Recalculation of unencrypted size aborted.');
525
-			return $unencryptedSize;
526
-		}
527
-
528
-		$newUnencryptedSize = 0;
529
-		$size -= $headerSize;
530
-		$blockSize = $this->util->getBlockSize();
531
-
532
-		// if a header exists we skip it
533
-		if ($headerSize > 0) {
534
-			fread($stream, $headerSize);
535
-		}
536
-
537
-		// fast path, else the calculation for $lastChunkNr is bogus
538
-		if ($size === 0) {
539
-			return 0;
540
-		}
541
-
542
-		$signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false;
543
-		$unencryptedBlockSize = $encryptionModule->getUnencryptedBlockSize($signed);
544
-
545
-		// calculate last chunk nr
546
-		// next highest is end of chunks, one subtracted is last one
547
-		// we have to read the last chunk, we can't just calculate it (because of padding etc)
548
-
549
-		$lastChunkNr = ceil($size/ $blockSize)-1;
550
-		// calculate last chunk position
551
-		$lastChunkPos = ($lastChunkNr * $blockSize);
552
-		// try to fseek to the last chunk, if it fails we have to read the whole file
553
-		if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) {
554
-			$newUnencryptedSize += $lastChunkNr * $unencryptedBlockSize;
555
-		}
556
-
557
-		$lastChunkContentEncrypted='';
558
-		$count = $blockSize;
559
-
560
-		while ($count > 0) {
561
-			$data=fread($stream, $blockSize);
562
-			$count=strlen($data);
563
-			$lastChunkContentEncrypted .= $data;
564
-			if(strlen($lastChunkContentEncrypted) > $blockSize) {
565
-				$newUnencryptedSize += $unencryptedBlockSize;
566
-				$lastChunkContentEncrypted=substr($lastChunkContentEncrypted, $blockSize);
567
-			}
568
-		}
569
-
570
-		fclose($stream);
571
-
572
-		// we have to decrypt the last chunk to get it actual size
573
-		$encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, []);
574
-		$decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr . 'end');
575
-		$decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr . 'end');
576
-
577
-		// calc the real file size with the size of the last chunk
578
-		$newUnencryptedSize += strlen($decryptedLastChunk);
579
-
580
-		$this->updateUnencryptedSize($this->getFullPath($path), $newUnencryptedSize);
581
-
582
-		// write to cache if applicable
583
-		$cache = $this->storage->getCache();
584
-		if ($cache) {
585
-			$entry = $cache->get($path);
586
-			$cache->update($entry['fileid'], ['size' => $newUnencryptedSize]);
587
-		}
588
-
589
-		return $newUnencryptedSize;
590
-	}
591
-
592
-	/**
593
-	 * @param Storage $sourceStorage
594
-	 * @param string $sourceInternalPath
595
-	 * @param string $targetInternalPath
596
-	 * @param bool $preserveMtime
597
-	 * @return bool
598
-	 */
599
-	public function moveFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = true) {
600
-		if ($sourceStorage === $this) {
601
-			return $this->rename($sourceInternalPath, $targetInternalPath);
602
-		}
603
-
604
-		// TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
605
-		// - call $this->storage->moveFromStorage() instead of $this->copyBetweenStorage
606
-		// - copy the file cache update from  $this->copyBetweenStorage to this method
607
-		// - copy the copyKeys() call from  $this->copyBetweenStorage to this method
608
-		// - remove $this->copyBetweenStorage
609
-
610
-		if (!$sourceStorage->isDeletable($sourceInternalPath)) {
611
-			return false;
612
-		}
613
-
614
-		$result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true);
615
-		if ($result) {
616
-			if ($sourceStorage->is_dir($sourceInternalPath)) {
617
-				$result &= $sourceStorage->rmdir($sourceInternalPath);
618
-			} else {
619
-				$result &= $sourceStorage->unlink($sourceInternalPath);
620
-			}
621
-		}
622
-		return $result;
623
-	}
624
-
625
-
626
-	/**
627
-	 * @param Storage $sourceStorage
628
-	 * @param string $sourceInternalPath
629
-	 * @param string $targetInternalPath
630
-	 * @param bool $preserveMtime
631
-	 * @param bool $isRename
632
-	 * @return bool
633
-	 */
634
-	public function copyFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false, $isRename = false) {
635
-
636
-		// TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
637
-		// - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage
638
-		// - copy the file cache update from  $this->copyBetweenStorage to this method
639
-		// - copy the copyKeys() call from  $this->copyBetweenStorage to this method
640
-		// - remove $this->copyBetweenStorage
641
-
642
-		return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename);
643
-	}
644
-
645
-	/**
646
-	 * Update the encrypted cache version in the database
647
-	 *
648
-	 * @param Storage $sourceStorage
649
-	 * @param string $sourceInternalPath
650
-	 * @param string $targetInternalPath
651
-	 * @param bool $isRename
652
-	 */
653
-	private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) {
654
-		$isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0;
655
-		$cacheInformation = [
656
-			'encrypted' => (bool)$isEncrypted,
657
-		];
658
-		if($isEncrypted === 1) {
659
-			$encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion'];
660
-
661
-			// In case of a move operation from an unencrypted to an encrypted
662
-			// storage the old encrypted version would stay with "0" while the
663
-			// correct value would be "1". Thus we manually set the value to "1"
664
-			// for those cases.
665
-			// See also https://github.com/owncloud/core/issues/23078
666
-			if($encryptedVersion === 0) {
667
-				$encryptedVersion = 1;
668
-			}
669
-
670
-			$cacheInformation['encryptedVersion'] = $encryptedVersion;
671
-		}
672
-
673
-		// in case of a rename we need to manipulate the source cache because
674
-		// this information will be kept for the new target
675
-		if ($isRename) {
676
-			$sourceStorage->getCache()->put($sourceInternalPath, $cacheInformation);
677
-		} else {
678
-			$this->getCache()->put($targetInternalPath, $cacheInformation);
679
-		}
680
-	}
681
-
682
-	/**
683
-	 * copy file between two storages
684
-	 *
685
-	 * @param Storage $sourceStorage
686
-	 * @param string $sourceInternalPath
687
-	 * @param string $targetInternalPath
688
-	 * @param bool $preserveMtime
689
-	 * @param bool $isRename
690
-	 * @return bool
691
-	 * @throws \Exception
692
-	 */
693
-	private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) {
694
-
695
-		// for versions we have nothing to do, because versions should always use the
696
-		// key from the original file. Just create a 1:1 copy and done
697
-		if ($this->isVersion($targetInternalPath) ||
698
-			$this->isVersion($sourceInternalPath)) {
699
-			// remember that we try to create a version so that we can detect it during
700
-			// fopen($sourceInternalPath) and by-pass the encryption in order to
701
-			// create a 1:1 copy of the file
702
-			$this->arrayCache->set('encryption_copy_version_' . $sourceInternalPath, true);
703
-			$result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
704
-			$this->arrayCache->remove('encryption_copy_version_' . $sourceInternalPath);
705
-			if ($result) {
706
-				$info = $this->getCache('', $sourceStorage)->get($sourceInternalPath);
707
-				// make sure that we update the unencrypted size for the version
708
-				if (isset($info['encrypted']) && $info['encrypted'] === true) {
709
-					$this->updateUnencryptedSize(
710
-						$this->getFullPath($targetInternalPath),
711
-						$info['size']
712
-					);
713
-				}
714
-				$this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
715
-			}
716
-			return $result;
717
-		}
718
-
719
-		// first copy the keys that we reuse the existing file key on the target location
720
-		// and don't create a new one which would break versions for example.
721
-		$mount = $this->mountManager->findByStorageId($sourceStorage->getId());
722
-		if (count($mount) === 1) {
723
-			$mountPoint = $mount[0]->getMountPoint();
724
-			$source = $mountPoint . '/' . $sourceInternalPath;
725
-			$target = $this->getFullPath($targetInternalPath);
726
-			$this->copyKeys($source, $target);
727
-		} else {
728
-			$this->logger->error('Could not find mount point, can\'t keep encryption keys');
729
-		}
730
-
731
-		if ($sourceStorage->is_dir($sourceInternalPath)) {
732
-			$dh = $sourceStorage->opendir($sourceInternalPath);
733
-			$result = $this->mkdir($targetInternalPath);
734
-			if (is_resource($dh)) {
735
-				while ($result and ($file = readdir($dh)) !== false) {
736
-					if (!Filesystem::isIgnoredDir($file)) {
737
-						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename);
738
-					}
739
-				}
740
-			}
741
-		} else {
742
-			try {
743
-				$source = $sourceStorage->fopen($sourceInternalPath, 'r');
744
-				$target = $this->fopen($targetInternalPath, 'w');
745
-				list(, $result) = \OC_Helper::streamCopy($source, $target);
746
-				fclose($source);
747
-				fclose($target);
748
-			} catch (\Exception $e) {
749
-				fclose($source);
750
-				fclose($target);
751
-				throw $e;
752
-			}
753
-			if($result) {
754
-				if ($preserveMtime) {
755
-					$this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
756
-				}
757
-				$this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
758
-			} else {
759
-				// delete partially written target file
760
-				$this->unlink($targetInternalPath);
761
-				// delete cache entry that was created by fopen
762
-				$this->getCache()->remove($targetInternalPath);
763
-			}
764
-		}
765
-		return (bool)$result;
766
-
767
-	}
768
-
769
-	/**
770
-	 * get the path to a local version of the file.
771
-	 * The local version of the file can be temporary and doesn't have to be persistent across requests
772
-	 *
773
-	 * @param string $path
774
-	 * @return string
775
-	 */
776
-	public function getLocalFile($path) {
777
-		if ($this->encryptionManager->isEnabled()) {
778
-			$cachedFile = $this->getCachedFile($path);
779
-			if (is_string($cachedFile)) {
780
-				return $cachedFile;
781
-			}
782
-		}
783
-		return $this->storage->getLocalFile($path);
784
-	}
785
-
786
-	/**
787
-	 * Returns the wrapped storage's value for isLocal()
788
-	 *
789
-	 * @return bool wrapped storage's isLocal() value
790
-	 */
791
-	public function isLocal() {
792
-		if ($this->encryptionManager->isEnabled()) {
793
-			return false;
794
-		}
795
-		return $this->storage->isLocal();
796
-	}
797
-
798
-	/**
799
-	 * see http://php.net/manual/en/function.stat.php
800
-	 * only the following keys are required in the result: size and mtime
801
-	 *
802
-	 * @param string $path
803
-	 * @return array
804
-	 */
805
-	public function stat($path) {
806
-		$stat = $this->storage->stat($path);
807
-		$fileSize = $this->filesize($path);
808
-		$stat['size'] = $fileSize;
809
-		$stat[7] = $fileSize;
810
-		return $stat;
811
-	}
812
-
813
-	/**
814
-	 * see http://php.net/manual/en/function.hash.php
815
-	 *
816
-	 * @param string $type
817
-	 * @param string $path
818
-	 * @param bool $raw
819
-	 * @return string
820
-	 */
821
-	public function hash($type, $path, $raw = false) {
822
-		$fh = $this->fopen($path, 'rb');
823
-		$ctx = hash_init($type);
824
-		hash_update_stream($ctx, $fh);
825
-		fclose($fh);
826
-		return hash_final($ctx, $raw);
827
-	}
828
-
829
-	/**
830
-	 * return full path, including mount point
831
-	 *
832
-	 * @param string $path relative to mount point
833
-	 * @return string full path including mount point
834
-	 */
835
-	protected function getFullPath($path) {
836
-		return Filesystem::normalizePath($this->mountPoint . '/' . $path);
837
-	}
838
-
839
-	/**
840
-	 * read first block of encrypted file, typically this will contain the
841
-	 * encryption header
842
-	 *
843
-	 * @param string $path
844
-	 * @return string
845
-	 */
846
-	protected function readFirstBlock($path) {
847
-		$firstBlock = '';
848
-		if ($this->storage->file_exists($path)) {
849
-			$handle = $this->storage->fopen($path, 'r');
850
-			$firstBlock = fread($handle, $this->util->getHeaderSize());
851
-			fclose($handle);
852
-		}
853
-		return $firstBlock;
854
-	}
855
-
856
-	/**
857
-	 * return header size of given file
858
-	 *
859
-	 * @param string $path
860
-	 * @return int
861
-	 */
862
-	protected function getHeaderSize($path) {
863
-		$headerSize = 0;
864
-		$realFile = $this->util->stripPartialFileExtension($path);
865
-		if ($this->storage->file_exists($realFile)) {
866
-			$path = $realFile;
867
-		}
868
-		$firstBlock = $this->readFirstBlock($path);
869
-
870
-		if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
871
-			$headerSize = $this->util->getHeaderSize();
872
-		}
873
-
874
-		return $headerSize;
875
-	}
876
-
877
-	/**
878
-	 * parse raw header to array
879
-	 *
880
-	 * @param string $rawHeader
881
-	 * @return array
882
-	 */
883
-	protected function parseRawHeader($rawHeader) {
884
-		$result = array();
885
-		if (substr($rawHeader, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
886
-			$header = $rawHeader;
887
-			$endAt = strpos($header, Util::HEADER_END);
888
-			if ($endAt !== false) {
889
-				$header = substr($header, 0, $endAt + strlen(Util::HEADER_END));
890
-
891
-				// +1 to not start with an ':' which would result in empty element at the beginning
892
-				$exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1));
893
-
894
-				$element = array_shift($exploded);
895
-				while ($element !== Util::HEADER_END) {
896
-					$result[$element] = array_shift($exploded);
897
-					$element = array_shift($exploded);
898
-				}
899
-			}
900
-		}
901
-
902
-		return $result;
903
-	}
904
-
905
-	/**
906
-	 * read header from file
907
-	 *
908
-	 * @param string $path
909
-	 * @return array
910
-	 */
911
-	protected function getHeader($path) {
912
-		$realFile = $this->util->stripPartialFileExtension($path);
913
-		if ($this->storage->file_exists($realFile)) {
914
-			$path = $realFile;
915
-		}
916
-
917
-		$firstBlock = $this->readFirstBlock($path);
918
-		$result = $this->parseRawHeader($firstBlock);
919
-
920
-		// if the header doesn't contain a encryption module we check if it is a
921
-		// legacy file. If true, we add the default encryption module
922
-		if (!isset($result[Util::HEADER_ENCRYPTION_MODULE_KEY])) {
923
-			if (!empty($result)) {
924
-				$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
925
-			} else {
926
-				// if the header was empty we have to check first if it is a encrypted file at all
927
-				$info = $this->getCache()->get($path);
928
-				if (isset($info['encrypted']) && $info['encrypted'] === true) {
929
-					$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
930
-				}
931
-			}
932
-		}
933
-
934
-		return $result;
935
-	}
936
-
937
-	/**
938
-	 * read encryption module needed to read/write the file located at $path
939
-	 *
940
-	 * @param string $path
941
-	 * @return null|\OCP\Encryption\IEncryptionModule
942
-	 * @throws ModuleDoesNotExistsException
943
-	 * @throws \Exception
944
-	 */
945
-	protected function getEncryptionModule($path) {
946
-		$encryptionModule = null;
947
-		$header = $this->getHeader($path);
948
-		$encryptionModuleId = $this->util->getEncryptionModuleId($header);
949
-		if (!empty($encryptionModuleId)) {
950
-			try {
951
-				$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
952
-			} catch (ModuleDoesNotExistsException $e) {
953
-				$this->logger->critical('Encryption module defined in "' . $path . '" not loaded!');
954
-				throw $e;
955
-			}
956
-		}
957
-		return $encryptionModule;
958
-	}
959
-
960
-	/**
961
-	 * @param string $path
962
-	 * @param int $unencryptedSize
963
-	 */
964
-	public function updateUnencryptedSize($path, $unencryptedSize) {
965
-		$this->unencryptedSize[$path] = $unencryptedSize;
966
-	}
967
-
968
-	/**
969
-	 * copy keys to new location
970
-	 *
971
-	 * @param string $source path relative to data/
972
-	 * @param string $target path relative to data/
973
-	 * @return bool
974
-	 */
975
-	protected function copyKeys($source, $target) {
976
-		if (!$this->util->isExcluded($source)) {
977
-			return $this->keyStorage->copyKeys($source, $target);
978
-		}
979
-
980
-		return false;
981
-	}
982
-
983
-	/**
984
-	 * check if path points to a files version
985
-	 *
986
-	 * @param $path
987
-	 * @return bool
988
-	 */
989
-	protected function isVersion($path) {
990
-		$normalized = Filesystem::normalizePath($path);
991
-		return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/';
992
-	}
49
+    use LocalTempFileTrait;
50
+
51
+    /** @var string */
52
+    private $mountPoint;
53
+
54
+    /** @var \OC\Encryption\Util */
55
+    private $util;
56
+
57
+    /** @var \OCP\Encryption\IManager */
58
+    private $encryptionManager;
59
+
60
+    /** @var \OCP\ILogger */
61
+    private $logger;
62
+
63
+    /** @var string */
64
+    private $uid;
65
+
66
+    /** @var array */
67
+    protected $unencryptedSize;
68
+
69
+    /** @var \OCP\Encryption\IFile */
70
+    private $fileHelper;
71
+
72
+    /** @var IMountPoint */
73
+    private $mount;
74
+
75
+    /** @var IStorage */
76
+    private $keyStorage;
77
+
78
+    /** @var Update */
79
+    private $update;
80
+
81
+    /** @var Manager */
82
+    private $mountManager;
83
+
84
+    /** @var array remember for which path we execute the repair step to avoid recursions */
85
+    private $fixUnencryptedSizeOf = array();
86
+
87
+    /** @var  ArrayCache */
88
+    private $arrayCache;
89
+
90
+    /**
91
+     * @param array $parameters
92
+     * @param IManager $encryptionManager
93
+     * @param Util $util
94
+     * @param ILogger $logger
95
+     * @param IFile $fileHelper
96
+     * @param string $uid
97
+     * @param IStorage $keyStorage
98
+     * @param Update $update
99
+     * @param Manager $mountManager
100
+     * @param ArrayCache $arrayCache
101
+     */
102
+    public function __construct(
103
+            $parameters,
104
+            IManager $encryptionManager = null,
105
+            Util $util = null,
106
+            ILogger $logger = null,
107
+            IFile $fileHelper = null,
108
+            $uid = null,
109
+            IStorage $keyStorage = null,
110
+            Update $update = null,
111
+            Manager $mountManager = null,
112
+            ArrayCache $arrayCache = null
113
+        ) {
114
+
115
+        $this->mountPoint = $parameters['mountPoint'];
116
+        $this->mount = $parameters['mount'];
117
+        $this->encryptionManager = $encryptionManager;
118
+        $this->util = $util;
119
+        $this->logger = $logger;
120
+        $this->uid = $uid;
121
+        $this->fileHelper = $fileHelper;
122
+        $this->keyStorage = $keyStorage;
123
+        $this->unencryptedSize = array();
124
+        $this->update = $update;
125
+        $this->mountManager = $mountManager;
126
+        $this->arrayCache = $arrayCache;
127
+        parent::__construct($parameters);
128
+    }
129
+
130
+    /**
131
+     * see http://php.net/manual/en/function.filesize.php
132
+     * The result for filesize when called on a folder is required to be 0
133
+     *
134
+     * @param string $path
135
+     * @return int
136
+     */
137
+    public function filesize($path) {
138
+        $fullPath = $this->getFullPath($path);
139
+
140
+        /** @var CacheEntry $info */
141
+        $info = $this->getCache()->get($path);
142
+        if (isset($this->unencryptedSize[$fullPath])) {
143
+            $size = $this->unencryptedSize[$fullPath];
144
+            // update file cache
145
+            if ($info instanceof ICacheEntry) {
146
+                $info = $info->getData();
147
+                $info['encrypted'] = $info['encryptedVersion'];
148
+            } else {
149
+                if (!is_array($info)) {
150
+                    $info = [];
151
+                }
152
+                $info['encrypted'] = true;
153
+            }
154
+
155
+            $info['size'] = $size;
156
+            $this->getCache()->put($path, $info);
157
+
158
+            return $size;
159
+        }
160
+
161
+        if (isset($info['fileid']) && $info['encrypted']) {
162
+            return $this->verifyUnencryptedSize($path, $info['size']);
163
+        }
164
+
165
+        return $this->storage->filesize($path);
166
+    }
167
+
168
+    /**
169
+     * @param string $path
170
+     * @return array
171
+     */
172
+    public function getMetaData($path) {
173
+        $data = $this->storage->getMetaData($path);
174
+        if (is_null($data)) {
175
+            return null;
176
+        }
177
+        $fullPath = $this->getFullPath($path);
178
+        $info = $this->getCache()->get($path);
179
+
180
+        if (isset($this->unencryptedSize[$fullPath])) {
181
+            $data['encrypted'] = true;
182
+            $data['size'] = $this->unencryptedSize[$fullPath];
183
+        } else {
184
+            if (isset($info['fileid']) && $info['encrypted']) {
185
+                $data['size'] = $this->verifyUnencryptedSize($path, $info['size']);
186
+                $data['encrypted'] = true;
187
+            }
188
+        }
189
+
190
+        if (isset($info['encryptedVersion']) && $info['encryptedVersion'] > 1) {
191
+            $data['encryptedVersion'] = $info['encryptedVersion'];
192
+        }
193
+
194
+        return $data;
195
+    }
196
+
197
+    /**
198
+     * see http://php.net/manual/en/function.file_get_contents.php
199
+     *
200
+     * @param string $path
201
+     * @return string
202
+     */
203
+    public function file_get_contents($path) {
204
+
205
+        $encryptionModule = $this->getEncryptionModule($path);
206
+
207
+        if ($encryptionModule) {
208
+            $handle = $this->fopen($path, "r");
209
+            if (!$handle) {
210
+                return false;
211
+            }
212
+            $data = stream_get_contents($handle);
213
+            fclose($handle);
214
+            return $data;
215
+        }
216
+        return $this->storage->file_get_contents($path);
217
+    }
218
+
219
+    /**
220
+     * see http://php.net/manual/en/function.file_put_contents.php
221
+     *
222
+     * @param string $path
223
+     * @param string $data
224
+     * @return bool
225
+     */
226
+    public function file_put_contents($path, $data) {
227
+        // file put content will always be translated to a stream write
228
+        $handle = $this->fopen($path, 'w');
229
+        if (is_resource($handle)) {
230
+            $written = fwrite($handle, $data);
231
+            fclose($handle);
232
+            return $written;
233
+        }
234
+
235
+        return false;
236
+    }
237
+
238
+    /**
239
+     * see http://php.net/manual/en/function.unlink.php
240
+     *
241
+     * @param string $path
242
+     * @return bool
243
+     */
244
+    public function unlink($path) {
245
+        $fullPath = $this->getFullPath($path);
246
+        if ($this->util->isExcluded($fullPath)) {
247
+            return $this->storage->unlink($path);
248
+        }
249
+
250
+        $encryptionModule = $this->getEncryptionModule($path);
251
+        if ($encryptionModule) {
252
+            $this->keyStorage->deleteAllFileKeys($this->getFullPath($path));
253
+        }
254
+
255
+        return $this->storage->unlink($path);
256
+    }
257
+
258
+    /**
259
+     * see http://php.net/manual/en/function.rename.php
260
+     *
261
+     * @param string $path1
262
+     * @param string $path2
263
+     * @return bool
264
+     */
265
+    public function rename($path1, $path2) {
266
+
267
+        $result = $this->storage->rename($path1, $path2);
268
+
269
+        if ($result &&
270
+            // versions always use the keys from the original file, so we can skip
271
+            // this step for versions
272
+            $this->isVersion($path2) === false &&
273
+            $this->encryptionManager->isEnabled()) {
274
+            $source = $this->getFullPath($path1);
275
+            if (!$this->util->isExcluded($source)) {
276
+                $target = $this->getFullPath($path2);
277
+                if (isset($this->unencryptedSize[$source])) {
278
+                    $this->unencryptedSize[$target] = $this->unencryptedSize[$source];
279
+                }
280
+                $this->keyStorage->renameKeys($source, $target);
281
+                $module = $this->getEncryptionModule($path2);
282
+                if ($module) {
283
+                    $module->update($target, $this->uid, []);
284
+                }
285
+            }
286
+        }
287
+
288
+        return $result;
289
+    }
290
+
291
+    /**
292
+     * see http://php.net/manual/en/function.rmdir.php
293
+     *
294
+     * @param string $path
295
+     * @return bool
296
+     */
297
+    public function rmdir($path) {
298
+        $result = $this->storage->rmdir($path);
299
+        $fullPath = $this->getFullPath($path);
300
+        if ($result &&
301
+            $this->util->isExcluded($fullPath) === false &&
302
+            $this->encryptionManager->isEnabled()
303
+        ) {
304
+            $this->keyStorage->deleteAllFileKeys($fullPath);
305
+        }
306
+
307
+        return $result;
308
+    }
309
+
310
+    /**
311
+     * check if a file can be read
312
+     *
313
+     * @param string $path
314
+     * @return bool
315
+     */
316
+    public function isReadable($path) {
317
+
318
+        $isReadable = true;
319
+
320
+        $metaData = $this->getMetaData($path);
321
+        if (
322
+            !$this->is_dir($path) &&
323
+            isset($metaData['encrypted']) &&
324
+            $metaData['encrypted'] === true
325
+        ) {
326
+            $fullPath = $this->getFullPath($path);
327
+            $module = $this->getEncryptionModule($path);
328
+            $isReadable = $module->isReadable($fullPath, $this->uid);
329
+        }
330
+
331
+        return $this->storage->isReadable($path) && $isReadable;
332
+    }
333
+
334
+    /**
335
+     * see http://php.net/manual/en/function.copy.php
336
+     *
337
+     * @param string $path1
338
+     * @param string $path2
339
+     * @return bool
340
+     */
341
+    public function copy($path1, $path2) {
342
+
343
+        $source = $this->getFullPath($path1);
344
+
345
+        if ($this->util->isExcluded($source)) {
346
+            return $this->storage->copy($path1, $path2);
347
+        }
348
+
349
+        // need to stream copy file by file in case we copy between a encrypted
350
+        // and a unencrypted storage
351
+        $this->unlink($path2);
352
+        $result = $this->copyFromStorage($this, $path1, $path2);
353
+
354
+        return $result;
355
+    }
356
+
357
+    /**
358
+     * see http://php.net/manual/en/function.fopen.php
359
+     *
360
+     * @param string $path
361
+     * @param string $mode
362
+     * @return resource|bool
363
+     * @throws GenericEncryptionException
364
+     * @throws ModuleDoesNotExistsException
365
+     */
366
+    public function fopen($path, $mode) {
367
+
368
+        // check if the file is stored in the array cache, this means that we
369
+        // copy a file over to the versions folder, in this case we don't want to
370
+        // decrypt it
371
+        if ($this->arrayCache->hasKey('encryption_copy_version_' . $path)) {
372
+            $this->arrayCache->remove('encryption_copy_version_' . $path);
373
+            return $this->storage->fopen($path, $mode);
374
+        }
375
+
376
+        $encryptionEnabled = $this->encryptionManager->isEnabled();
377
+        $shouldEncrypt = false;
378
+        $encryptionModule = null;
379
+        $header = $this->getHeader($path);
380
+        $signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false;
381
+        $fullPath = $this->getFullPath($path);
382
+        $encryptionModuleId = $this->util->getEncryptionModuleId($header);
383
+
384
+        if ($this->util->isExcluded($fullPath) === false) {
385
+
386
+            $size = $unencryptedSize = 0;
387
+            $realFile = $this->util->stripPartialFileExtension($path);
388
+            $targetExists = $this->file_exists($realFile) || $this->file_exists($path);
389
+            $targetIsEncrypted = false;
390
+            if ($targetExists) {
391
+                // in case the file exists we require the explicit module as
392
+                // specified in the file header - otherwise we need to fail hard to
393
+                // prevent data loss on client side
394
+                if (!empty($encryptionModuleId)) {
395
+                    $targetIsEncrypted = true;
396
+                    $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
397
+                }
398
+
399
+                if ($this->file_exists($path)) {
400
+                    $size = $this->storage->filesize($path);
401
+                    $unencryptedSize = $this->filesize($path);
402
+                } else {
403
+                    $size = $unencryptedSize = 0;
404
+                }
405
+            }
406
+
407
+            try {
408
+
409
+                if (
410
+                    $mode === 'w'
411
+                    || $mode === 'w+'
412
+                    || $mode === 'wb'
413
+                    || $mode === 'wb+'
414
+                ) {
415
+                    // don't overwrite encrypted files if encryption is not enabled
416
+                    if ($targetIsEncrypted && $encryptionEnabled === false) {
417
+                        throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled');
418
+                    }
419
+                    if ($encryptionEnabled) {
420
+                        // if $encryptionModuleId is empty, the default module will be used
421
+                        $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
422
+                        $shouldEncrypt = $encryptionModule->shouldEncrypt($fullPath);
423
+                        $signed = true;
424
+                    }
425
+                } else {
426
+                    $info = $this->getCache()->get($path);
427
+                    // only get encryption module if we found one in the header
428
+                    // or if file should be encrypted according to the file cache
429
+                    if (!empty($encryptionModuleId)) {
430
+                        $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
431
+                        $shouldEncrypt = true;
432
+                    } else if (empty($encryptionModuleId) && $info['encrypted'] === true) {
433
+                        // we come from a old installation. No header and/or no module defined
434
+                        // but the file is encrypted. In this case we need to use the
435
+                        // OC_DEFAULT_MODULE to read the file
436
+                        $encryptionModule = $this->encryptionManager->getEncryptionModule('OC_DEFAULT_MODULE');
437
+                        $shouldEncrypt = true;
438
+                        $targetIsEncrypted = true;
439
+                    }
440
+                }
441
+            } catch (ModuleDoesNotExistsException $e) {
442
+                $this->logger->warning('Encryption module "' . $encryptionModuleId .
443
+                    '" not found, file will be stored unencrypted (' . $e->getMessage() . ')');
444
+            }
445
+
446
+            // encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt
447
+            if (!$encryptionEnabled || !$this->mount->getOption('encrypt', true)) {
448
+                if (!$targetExists || !$targetIsEncrypted) {
449
+                    $shouldEncrypt = false;
450
+                }
451
+            }
452
+
453
+            if ($shouldEncrypt === true && $encryptionModule !== null) {
454
+                $headerSize = $this->getHeaderSize($path);
455
+                $source = $this->storage->fopen($path, $mode);
456
+                if (!is_resource($source)) {
457
+                    return false;
458
+                }
459
+                $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header,
460
+                    $this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode,
461
+                    $size, $unencryptedSize, $headerSize, $signed);
462
+                return $handle;
463
+            }
464
+
465
+        }
466
+
467
+        return $this->storage->fopen($path, $mode);
468
+    }
469
+
470
+
471
+    /**
472
+     * perform some plausibility checks if the the unencrypted size is correct.
473
+     * If not, we calculate the correct unencrypted size and return it
474
+     *
475
+     * @param string $path internal path relative to the storage root
476
+     * @param int $unencryptedSize size of the unencrypted file
477
+     *
478
+     * @return int unencrypted size
479
+     */
480
+    protected function verifyUnencryptedSize($path, $unencryptedSize) {
481
+
482
+        $size = $this->storage->filesize($path);
483
+        $result = $unencryptedSize;
484
+
485
+        if ($unencryptedSize < 0 ||
486
+            ($size > 0 && $unencryptedSize === $size)
487
+        ) {
488
+            // check if we already calculate the unencrypted size for the
489
+            // given path to avoid recursions
490
+            if (isset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]) === false) {
491
+                $this->fixUnencryptedSizeOf[$this->getFullPath($path)] = true;
492
+                try {
493
+                    $result = $this->fixUnencryptedSize($path, $size, $unencryptedSize);
494
+                } catch (\Exception $e) {
495
+                    $this->logger->error('Couldn\'t re-calculate unencrypted size for '. $path);
496
+                    $this->logger->logException($e);
497
+                }
498
+                unset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]);
499
+            }
500
+        }
501
+
502
+        return $result;
503
+    }
504
+
505
+    /**
506
+     * calculate the unencrypted size
507
+     *
508
+     * @param string $path internal path relative to the storage root
509
+     * @param int $size size of the physical file
510
+     * @param int $unencryptedSize size of the unencrypted file
511
+     *
512
+     * @return int calculated unencrypted size
513
+     */
514
+    protected function fixUnencryptedSize($path, $size, $unencryptedSize) {
515
+
516
+        $headerSize = $this->getHeaderSize($path);
517
+        $header = $this->getHeader($path);
518
+        $encryptionModule = $this->getEncryptionModule($path);
519
+
520
+        $stream = $this->storage->fopen($path, 'r');
521
+
522
+        // if we couldn't open the file we return the old unencrypted size
523
+        if (!is_resource($stream)) {
524
+            $this->logger->error('Could not open ' . $path . '. Recalculation of unencrypted size aborted.');
525
+            return $unencryptedSize;
526
+        }
527
+
528
+        $newUnencryptedSize = 0;
529
+        $size -= $headerSize;
530
+        $blockSize = $this->util->getBlockSize();
531
+
532
+        // if a header exists we skip it
533
+        if ($headerSize > 0) {
534
+            fread($stream, $headerSize);
535
+        }
536
+
537
+        // fast path, else the calculation for $lastChunkNr is bogus
538
+        if ($size === 0) {
539
+            return 0;
540
+        }
541
+
542
+        $signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false;
543
+        $unencryptedBlockSize = $encryptionModule->getUnencryptedBlockSize($signed);
544
+
545
+        // calculate last chunk nr
546
+        // next highest is end of chunks, one subtracted is last one
547
+        // we have to read the last chunk, we can't just calculate it (because of padding etc)
548
+
549
+        $lastChunkNr = ceil($size/ $blockSize)-1;
550
+        // calculate last chunk position
551
+        $lastChunkPos = ($lastChunkNr * $blockSize);
552
+        // try to fseek to the last chunk, if it fails we have to read the whole file
553
+        if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) {
554
+            $newUnencryptedSize += $lastChunkNr * $unencryptedBlockSize;
555
+        }
556
+
557
+        $lastChunkContentEncrypted='';
558
+        $count = $blockSize;
559
+
560
+        while ($count > 0) {
561
+            $data=fread($stream, $blockSize);
562
+            $count=strlen($data);
563
+            $lastChunkContentEncrypted .= $data;
564
+            if(strlen($lastChunkContentEncrypted) > $blockSize) {
565
+                $newUnencryptedSize += $unencryptedBlockSize;
566
+                $lastChunkContentEncrypted=substr($lastChunkContentEncrypted, $blockSize);
567
+            }
568
+        }
569
+
570
+        fclose($stream);
571
+
572
+        // we have to decrypt the last chunk to get it actual size
573
+        $encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, []);
574
+        $decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr . 'end');
575
+        $decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr . 'end');
576
+
577
+        // calc the real file size with the size of the last chunk
578
+        $newUnencryptedSize += strlen($decryptedLastChunk);
579
+
580
+        $this->updateUnencryptedSize($this->getFullPath($path), $newUnencryptedSize);
581
+
582
+        // write to cache if applicable
583
+        $cache = $this->storage->getCache();
584
+        if ($cache) {
585
+            $entry = $cache->get($path);
586
+            $cache->update($entry['fileid'], ['size' => $newUnencryptedSize]);
587
+        }
588
+
589
+        return $newUnencryptedSize;
590
+    }
591
+
592
+    /**
593
+     * @param Storage $sourceStorage
594
+     * @param string $sourceInternalPath
595
+     * @param string $targetInternalPath
596
+     * @param bool $preserveMtime
597
+     * @return bool
598
+     */
599
+    public function moveFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = true) {
600
+        if ($sourceStorage === $this) {
601
+            return $this->rename($sourceInternalPath, $targetInternalPath);
602
+        }
603
+
604
+        // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
605
+        // - call $this->storage->moveFromStorage() instead of $this->copyBetweenStorage
606
+        // - copy the file cache update from  $this->copyBetweenStorage to this method
607
+        // - copy the copyKeys() call from  $this->copyBetweenStorage to this method
608
+        // - remove $this->copyBetweenStorage
609
+
610
+        if (!$sourceStorage->isDeletable($sourceInternalPath)) {
611
+            return false;
612
+        }
613
+
614
+        $result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true);
615
+        if ($result) {
616
+            if ($sourceStorage->is_dir($sourceInternalPath)) {
617
+                $result &= $sourceStorage->rmdir($sourceInternalPath);
618
+            } else {
619
+                $result &= $sourceStorage->unlink($sourceInternalPath);
620
+            }
621
+        }
622
+        return $result;
623
+    }
624
+
625
+
626
+    /**
627
+     * @param Storage $sourceStorage
628
+     * @param string $sourceInternalPath
629
+     * @param string $targetInternalPath
630
+     * @param bool $preserveMtime
631
+     * @param bool $isRename
632
+     * @return bool
633
+     */
634
+    public function copyFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false, $isRename = false) {
635
+
636
+        // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
637
+        // - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage
638
+        // - copy the file cache update from  $this->copyBetweenStorage to this method
639
+        // - copy the copyKeys() call from  $this->copyBetweenStorage to this method
640
+        // - remove $this->copyBetweenStorage
641
+
642
+        return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename);
643
+    }
644
+
645
+    /**
646
+     * Update the encrypted cache version in the database
647
+     *
648
+     * @param Storage $sourceStorage
649
+     * @param string $sourceInternalPath
650
+     * @param string $targetInternalPath
651
+     * @param bool $isRename
652
+     */
653
+    private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) {
654
+        $isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0;
655
+        $cacheInformation = [
656
+            'encrypted' => (bool)$isEncrypted,
657
+        ];
658
+        if($isEncrypted === 1) {
659
+            $encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion'];
660
+
661
+            // In case of a move operation from an unencrypted to an encrypted
662
+            // storage the old encrypted version would stay with "0" while the
663
+            // correct value would be "1". Thus we manually set the value to "1"
664
+            // for those cases.
665
+            // See also https://github.com/owncloud/core/issues/23078
666
+            if($encryptedVersion === 0) {
667
+                $encryptedVersion = 1;
668
+            }
669
+
670
+            $cacheInformation['encryptedVersion'] = $encryptedVersion;
671
+        }
672
+
673
+        // in case of a rename we need to manipulate the source cache because
674
+        // this information will be kept for the new target
675
+        if ($isRename) {
676
+            $sourceStorage->getCache()->put($sourceInternalPath, $cacheInformation);
677
+        } else {
678
+            $this->getCache()->put($targetInternalPath, $cacheInformation);
679
+        }
680
+    }
681
+
682
+    /**
683
+     * copy file between two storages
684
+     *
685
+     * @param Storage $sourceStorage
686
+     * @param string $sourceInternalPath
687
+     * @param string $targetInternalPath
688
+     * @param bool $preserveMtime
689
+     * @param bool $isRename
690
+     * @return bool
691
+     * @throws \Exception
692
+     */
693
+    private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) {
694
+
695
+        // for versions we have nothing to do, because versions should always use the
696
+        // key from the original file. Just create a 1:1 copy and done
697
+        if ($this->isVersion($targetInternalPath) ||
698
+            $this->isVersion($sourceInternalPath)) {
699
+            // remember that we try to create a version so that we can detect it during
700
+            // fopen($sourceInternalPath) and by-pass the encryption in order to
701
+            // create a 1:1 copy of the file
702
+            $this->arrayCache->set('encryption_copy_version_' . $sourceInternalPath, true);
703
+            $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
704
+            $this->arrayCache->remove('encryption_copy_version_' . $sourceInternalPath);
705
+            if ($result) {
706
+                $info = $this->getCache('', $sourceStorage)->get($sourceInternalPath);
707
+                // make sure that we update the unencrypted size for the version
708
+                if (isset($info['encrypted']) && $info['encrypted'] === true) {
709
+                    $this->updateUnencryptedSize(
710
+                        $this->getFullPath($targetInternalPath),
711
+                        $info['size']
712
+                    );
713
+                }
714
+                $this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
715
+            }
716
+            return $result;
717
+        }
718
+
719
+        // first copy the keys that we reuse the existing file key on the target location
720
+        // and don't create a new one which would break versions for example.
721
+        $mount = $this->mountManager->findByStorageId($sourceStorage->getId());
722
+        if (count($mount) === 1) {
723
+            $mountPoint = $mount[0]->getMountPoint();
724
+            $source = $mountPoint . '/' . $sourceInternalPath;
725
+            $target = $this->getFullPath($targetInternalPath);
726
+            $this->copyKeys($source, $target);
727
+        } else {
728
+            $this->logger->error('Could not find mount point, can\'t keep encryption keys');
729
+        }
730
+
731
+        if ($sourceStorage->is_dir($sourceInternalPath)) {
732
+            $dh = $sourceStorage->opendir($sourceInternalPath);
733
+            $result = $this->mkdir($targetInternalPath);
734
+            if (is_resource($dh)) {
735
+                while ($result and ($file = readdir($dh)) !== false) {
736
+                    if (!Filesystem::isIgnoredDir($file)) {
737
+                        $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename);
738
+                    }
739
+                }
740
+            }
741
+        } else {
742
+            try {
743
+                $source = $sourceStorage->fopen($sourceInternalPath, 'r');
744
+                $target = $this->fopen($targetInternalPath, 'w');
745
+                list(, $result) = \OC_Helper::streamCopy($source, $target);
746
+                fclose($source);
747
+                fclose($target);
748
+            } catch (\Exception $e) {
749
+                fclose($source);
750
+                fclose($target);
751
+                throw $e;
752
+            }
753
+            if($result) {
754
+                if ($preserveMtime) {
755
+                    $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
756
+                }
757
+                $this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
758
+            } else {
759
+                // delete partially written target file
760
+                $this->unlink($targetInternalPath);
761
+                // delete cache entry that was created by fopen
762
+                $this->getCache()->remove($targetInternalPath);
763
+            }
764
+        }
765
+        return (bool)$result;
766
+
767
+    }
768
+
769
+    /**
770
+     * get the path to a local version of the file.
771
+     * The local version of the file can be temporary and doesn't have to be persistent across requests
772
+     *
773
+     * @param string $path
774
+     * @return string
775
+     */
776
+    public function getLocalFile($path) {
777
+        if ($this->encryptionManager->isEnabled()) {
778
+            $cachedFile = $this->getCachedFile($path);
779
+            if (is_string($cachedFile)) {
780
+                return $cachedFile;
781
+            }
782
+        }
783
+        return $this->storage->getLocalFile($path);
784
+    }
785
+
786
+    /**
787
+     * Returns the wrapped storage's value for isLocal()
788
+     *
789
+     * @return bool wrapped storage's isLocal() value
790
+     */
791
+    public function isLocal() {
792
+        if ($this->encryptionManager->isEnabled()) {
793
+            return false;
794
+        }
795
+        return $this->storage->isLocal();
796
+    }
797
+
798
+    /**
799
+     * see http://php.net/manual/en/function.stat.php
800
+     * only the following keys are required in the result: size and mtime
801
+     *
802
+     * @param string $path
803
+     * @return array
804
+     */
805
+    public function stat($path) {
806
+        $stat = $this->storage->stat($path);
807
+        $fileSize = $this->filesize($path);
808
+        $stat['size'] = $fileSize;
809
+        $stat[7] = $fileSize;
810
+        return $stat;
811
+    }
812
+
813
+    /**
814
+     * see http://php.net/manual/en/function.hash.php
815
+     *
816
+     * @param string $type
817
+     * @param string $path
818
+     * @param bool $raw
819
+     * @return string
820
+     */
821
+    public function hash($type, $path, $raw = false) {
822
+        $fh = $this->fopen($path, 'rb');
823
+        $ctx = hash_init($type);
824
+        hash_update_stream($ctx, $fh);
825
+        fclose($fh);
826
+        return hash_final($ctx, $raw);
827
+    }
828
+
829
+    /**
830
+     * return full path, including mount point
831
+     *
832
+     * @param string $path relative to mount point
833
+     * @return string full path including mount point
834
+     */
835
+    protected function getFullPath($path) {
836
+        return Filesystem::normalizePath($this->mountPoint . '/' . $path);
837
+    }
838
+
839
+    /**
840
+     * read first block of encrypted file, typically this will contain the
841
+     * encryption header
842
+     *
843
+     * @param string $path
844
+     * @return string
845
+     */
846
+    protected function readFirstBlock($path) {
847
+        $firstBlock = '';
848
+        if ($this->storage->file_exists($path)) {
849
+            $handle = $this->storage->fopen($path, 'r');
850
+            $firstBlock = fread($handle, $this->util->getHeaderSize());
851
+            fclose($handle);
852
+        }
853
+        return $firstBlock;
854
+    }
855
+
856
+    /**
857
+     * return header size of given file
858
+     *
859
+     * @param string $path
860
+     * @return int
861
+     */
862
+    protected function getHeaderSize($path) {
863
+        $headerSize = 0;
864
+        $realFile = $this->util->stripPartialFileExtension($path);
865
+        if ($this->storage->file_exists($realFile)) {
866
+            $path = $realFile;
867
+        }
868
+        $firstBlock = $this->readFirstBlock($path);
869
+
870
+        if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
871
+            $headerSize = $this->util->getHeaderSize();
872
+        }
873
+
874
+        return $headerSize;
875
+    }
876
+
877
+    /**
878
+     * parse raw header to array
879
+     *
880
+     * @param string $rawHeader
881
+     * @return array
882
+     */
883
+    protected function parseRawHeader($rawHeader) {
884
+        $result = array();
885
+        if (substr($rawHeader, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
886
+            $header = $rawHeader;
887
+            $endAt = strpos($header, Util::HEADER_END);
888
+            if ($endAt !== false) {
889
+                $header = substr($header, 0, $endAt + strlen(Util::HEADER_END));
890
+
891
+                // +1 to not start with an ':' which would result in empty element at the beginning
892
+                $exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1));
893
+
894
+                $element = array_shift($exploded);
895
+                while ($element !== Util::HEADER_END) {
896
+                    $result[$element] = array_shift($exploded);
897
+                    $element = array_shift($exploded);
898
+                }
899
+            }
900
+        }
901
+
902
+        return $result;
903
+    }
904
+
905
+    /**
906
+     * read header from file
907
+     *
908
+     * @param string $path
909
+     * @return array
910
+     */
911
+    protected function getHeader($path) {
912
+        $realFile = $this->util->stripPartialFileExtension($path);
913
+        if ($this->storage->file_exists($realFile)) {
914
+            $path = $realFile;
915
+        }
916
+
917
+        $firstBlock = $this->readFirstBlock($path);
918
+        $result = $this->parseRawHeader($firstBlock);
919
+
920
+        // if the header doesn't contain a encryption module we check if it is a
921
+        // legacy file. If true, we add the default encryption module
922
+        if (!isset($result[Util::HEADER_ENCRYPTION_MODULE_KEY])) {
923
+            if (!empty($result)) {
924
+                $result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
925
+            } else {
926
+                // if the header was empty we have to check first if it is a encrypted file at all
927
+                $info = $this->getCache()->get($path);
928
+                if (isset($info['encrypted']) && $info['encrypted'] === true) {
929
+                    $result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
930
+                }
931
+            }
932
+        }
933
+
934
+        return $result;
935
+    }
936
+
937
+    /**
938
+     * read encryption module needed to read/write the file located at $path
939
+     *
940
+     * @param string $path
941
+     * @return null|\OCP\Encryption\IEncryptionModule
942
+     * @throws ModuleDoesNotExistsException
943
+     * @throws \Exception
944
+     */
945
+    protected function getEncryptionModule($path) {
946
+        $encryptionModule = null;
947
+        $header = $this->getHeader($path);
948
+        $encryptionModuleId = $this->util->getEncryptionModuleId($header);
949
+        if (!empty($encryptionModuleId)) {
950
+            try {
951
+                $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
952
+            } catch (ModuleDoesNotExistsException $e) {
953
+                $this->logger->critical('Encryption module defined in "' . $path . '" not loaded!');
954
+                throw $e;
955
+            }
956
+        }
957
+        return $encryptionModule;
958
+    }
959
+
960
+    /**
961
+     * @param string $path
962
+     * @param int $unencryptedSize
963
+     */
964
+    public function updateUnencryptedSize($path, $unencryptedSize) {
965
+        $this->unencryptedSize[$path] = $unencryptedSize;
966
+    }
967
+
968
+    /**
969
+     * copy keys to new location
970
+     *
971
+     * @param string $source path relative to data/
972
+     * @param string $target path relative to data/
973
+     * @return bool
974
+     */
975
+    protected function copyKeys($source, $target) {
976
+        if (!$this->util->isExcluded($source)) {
977
+            return $this->keyStorage->copyKeys($source, $target);
978
+        }
979
+
980
+        return false;
981
+    }
982
+
983
+    /**
984
+     * check if path points to a files version
985
+     *
986
+     * @param $path
987
+     * @return bool
988
+     */
989
+    protected function isVersion($path) {
990
+        $normalized = Filesystem::normalizePath($path);
991
+        return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/';
992
+    }
993 993
 
994 994
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -368,8 +368,8 @@  discard block
 block discarded – undo
368 368
 		// check if the file is stored in the array cache, this means that we
369 369
 		// copy a file over to the versions folder, in this case we don't want to
370 370
 		// decrypt it
371
-		if ($this->arrayCache->hasKey('encryption_copy_version_' . $path)) {
372
-			$this->arrayCache->remove('encryption_copy_version_' . $path);
371
+		if ($this->arrayCache->hasKey('encryption_copy_version_'.$path)) {
372
+			$this->arrayCache->remove('encryption_copy_version_'.$path);
373 373
 			return $this->storage->fopen($path, $mode);
374 374
 		}
375 375
 
@@ -439,8 +439,8 @@  discard block
 block discarded – undo
439 439
 					}
440 440
 				}
441 441
 			} catch (ModuleDoesNotExistsException $e) {
442
-				$this->logger->warning('Encryption module "' . $encryptionModuleId .
443
-					'" not found, file will be stored unencrypted (' . $e->getMessage() . ')');
442
+				$this->logger->warning('Encryption module "'.$encryptionModuleId.
443
+					'" not found, file will be stored unencrypted ('.$e->getMessage().')');
444 444
 			}
445 445
 
446 446
 			// encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt
@@ -492,7 +492,7 @@  discard block
 block discarded – undo
492 492
 				try {
493 493
 					$result = $this->fixUnencryptedSize($path, $size, $unencryptedSize);
494 494
 				} catch (\Exception $e) {
495
-					$this->logger->error('Couldn\'t re-calculate unencrypted size for '. $path);
495
+					$this->logger->error('Couldn\'t re-calculate unencrypted size for '.$path);
496 496
 					$this->logger->logException($e);
497 497
 				}
498 498
 				unset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]);
@@ -521,7 +521,7 @@  discard block
 block discarded – undo
521 521
 
522 522
 		// if we couldn't open the file we return the old unencrypted size
523 523
 		if (!is_resource($stream)) {
524
-			$this->logger->error('Could not open ' . $path . '. Recalculation of unencrypted size aborted.');
524
+			$this->logger->error('Could not open '.$path.'. Recalculation of unencrypted size aborted.');
525 525
 			return $unencryptedSize;
526 526
 		}
527 527
 
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
 		// next highest is end of chunks, one subtracted is last one
547 547
 		// we have to read the last chunk, we can't just calculate it (because of padding etc)
548 548
 
549
-		$lastChunkNr = ceil($size/ $blockSize)-1;
549
+		$lastChunkNr = ceil($size / $blockSize) - 1;
550 550
 		// calculate last chunk position
551 551
 		$lastChunkPos = ($lastChunkNr * $blockSize);
552 552
 		// try to fseek to the last chunk, if it fails we have to read the whole file
@@ -554,16 +554,16 @@  discard block
 block discarded – undo
554 554
 			$newUnencryptedSize += $lastChunkNr * $unencryptedBlockSize;
555 555
 		}
556 556
 
557
-		$lastChunkContentEncrypted='';
557
+		$lastChunkContentEncrypted = '';
558 558
 		$count = $blockSize;
559 559
 
560 560
 		while ($count > 0) {
561
-			$data=fread($stream, $blockSize);
562
-			$count=strlen($data);
561
+			$data = fread($stream, $blockSize);
562
+			$count = strlen($data);
563 563
 			$lastChunkContentEncrypted .= $data;
564
-			if(strlen($lastChunkContentEncrypted) > $blockSize) {
564
+			if (strlen($lastChunkContentEncrypted) > $blockSize) {
565 565
 				$newUnencryptedSize += $unencryptedBlockSize;
566
-				$lastChunkContentEncrypted=substr($lastChunkContentEncrypted, $blockSize);
566
+				$lastChunkContentEncrypted = substr($lastChunkContentEncrypted, $blockSize);
567 567
 			}
568 568
 		}
569 569
 
@@ -571,8 +571,8 @@  discard block
 block discarded – undo
571 571
 
572 572
 		// we have to decrypt the last chunk to get it actual size
573 573
 		$encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, []);
574
-		$decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr . 'end');
575
-		$decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr . 'end');
574
+		$decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr.'end');
575
+		$decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr.'end');
576 576
 
577 577
 		// calc the real file size with the size of the last chunk
578 578
 		$newUnencryptedSize += strlen($decryptedLastChunk);
@@ -653,9 +653,9 @@  discard block
 block discarded – undo
653 653
 	private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) {
654 654
 		$isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0;
655 655
 		$cacheInformation = [
656
-			'encrypted' => (bool)$isEncrypted,
656
+			'encrypted' => (bool) $isEncrypted,
657 657
 		];
658
-		if($isEncrypted === 1) {
658
+		if ($isEncrypted === 1) {
659 659
 			$encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion'];
660 660
 
661 661
 			// In case of a move operation from an unencrypted to an encrypted
@@ -663,7 +663,7 @@  discard block
 block discarded – undo
663 663
 			// correct value would be "1". Thus we manually set the value to "1"
664 664
 			// for those cases.
665 665
 			// See also https://github.com/owncloud/core/issues/23078
666
-			if($encryptedVersion === 0) {
666
+			if ($encryptedVersion === 0) {
667 667
 				$encryptedVersion = 1;
668 668
 			}
669 669
 
@@ -699,9 +699,9 @@  discard block
 block discarded – undo
699 699
 			// remember that we try to create a version so that we can detect it during
700 700
 			// fopen($sourceInternalPath) and by-pass the encryption in order to
701 701
 			// create a 1:1 copy of the file
702
-			$this->arrayCache->set('encryption_copy_version_' . $sourceInternalPath, true);
702
+			$this->arrayCache->set('encryption_copy_version_'.$sourceInternalPath, true);
703 703
 			$result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
704
-			$this->arrayCache->remove('encryption_copy_version_' . $sourceInternalPath);
704
+			$this->arrayCache->remove('encryption_copy_version_'.$sourceInternalPath);
705 705
 			if ($result) {
706 706
 				$info = $this->getCache('', $sourceStorage)->get($sourceInternalPath);
707 707
 				// make sure that we update the unencrypted size for the version
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
 		$mount = $this->mountManager->findByStorageId($sourceStorage->getId());
722 722
 		if (count($mount) === 1) {
723 723
 			$mountPoint = $mount[0]->getMountPoint();
724
-			$source = $mountPoint . '/' . $sourceInternalPath;
724
+			$source = $mountPoint.'/'.$sourceInternalPath;
725 725
 			$target = $this->getFullPath($targetInternalPath);
726 726
 			$this->copyKeys($source, $target);
727 727
 		} else {
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
 			if (is_resource($dh)) {
735 735
 				while ($result and ($file = readdir($dh)) !== false) {
736 736
 					if (!Filesystem::isIgnoredDir($file)) {
737
-						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename);
737
+						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath.'/'.$file, $targetInternalPath.'/'.$file, false, $isRename);
738 738
 					}
739 739
 				}
740 740
 			}
@@ -750,7 +750,7 @@  discard block
 block discarded – undo
750 750
 				fclose($target);
751 751
 				throw $e;
752 752
 			}
753
-			if($result) {
753
+			if ($result) {
754 754
 				if ($preserveMtime) {
755 755
 					$this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
756 756
 				}
@@ -762,7 +762,7 @@  discard block
 block discarded – undo
762 762
 				$this->getCache()->remove($targetInternalPath);
763 763
 			}
764 764
 		}
765
-		return (bool)$result;
765
+		return (bool) $result;
766 766
 
767 767
 	}
768 768
 
@@ -833,7 +833,7 @@  discard block
 block discarded – undo
833 833
 	 * @return string full path including mount point
834 834
 	 */
835 835
 	protected function getFullPath($path) {
836
-		return Filesystem::normalizePath($this->mountPoint . '/' . $path);
836
+		return Filesystem::normalizePath($this->mountPoint.'/'.$path);
837 837
 	}
838 838
 
839 839
 	/**
@@ -889,7 +889,7 @@  discard block
 block discarded – undo
889 889
 				$header = substr($header, 0, $endAt + strlen(Util::HEADER_END));
890 890
 
891 891
 				// +1 to not start with an ':' which would result in empty element at the beginning
892
-				$exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1));
892
+				$exploded = explode(':', substr($header, strlen(Util::HEADER_START) + 1));
893 893
 
894 894
 				$element = array_shift($exploded);
895 895
 				while ($element !== Util::HEADER_END) {
@@ -950,7 +950,7 @@  discard block
 block discarded – undo
950 950
 			try {
951 951
 				$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
952 952
 			} catch (ModuleDoesNotExistsException $e) {
953
-				$this->logger->critical('Encryption module defined in "' . $path . '" not loaded!');
953
+				$this->logger->critical('Encryption module defined in "'.$path.'" not loaded!');
954 954
 				throw $e;
955 955
 			}
956 956
 		}
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Quota.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -159,7 +159,7 @@
 block discarded – undo
159 159
 	 * Checks whether the given path is a part file
160 160
 	 *
161 161
 	 * @param string $path Path that may identify a .part file
162
-	 * @return string File path without .part extension
162
+	 * @return boolean File path without .part extension
163 163
 	 * @note this is needed for reusing keys
164 164
 	 */
165 165
 	private function isPartFile($path) {
Please login to merge, or discard this patch.
Indentation   +168 added lines, -168 removed lines patch added patch discarded remove patch
@@ -30,172 +30,172 @@
 block discarded – undo
30 30
 
31 31
 class Quota extends Wrapper {
32 32
 
33
-	/**
34
-	 * @var int $quota
35
-	 */
36
-	protected $quota;
37
-
38
-	/**
39
-	 * @var string $sizeRoot
40
-	 */
41
-	protected $sizeRoot;
42
-
43
-	/**
44
-	 * @param array $parameters
45
-	 */
46
-	public function __construct($parameters) {
47
-		$this->storage = $parameters['storage'];
48
-		$this->quota = $parameters['quota'];
49
-		$this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
50
-	}
51
-
52
-	/**
53
-	 * @return int quota value
54
-	 */
55
-	public function getQuota() {
56
-		return $this->quota;
57
-	}
58
-
59
-	/**
60
-	 * @param string $path
61
-	 * @param \OC\Files\Storage\Storage $storage
62
-	 */
63
-	protected function getSize($path, $storage = null) {
64
-		if (is_null($storage)) {
65
-			$cache = $this->getCache();
66
-		} else {
67
-			$cache = $storage->getCache();
68
-		}
69
-		$data = $cache->get($path);
70
-		if ($data instanceof ICacheEntry and isset($data['size'])) {
71
-			return $data['size'];
72
-		} else {
73
-			return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
74
-		}
75
-	}
76
-
77
-	/**
78
-	 * Get free space as limited by the quota
79
-	 *
80
-	 * @param string $path
81
-	 * @return int
82
-	 */
83
-	public function free_space($path) {
84
-		if ($this->quota < 0) {
85
-			return $this->storage->free_space($path);
86
-		} else {
87
-			$used = $this->getSize($this->sizeRoot);
88
-			if ($used < 0) {
89
-				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
90
-			} else {
91
-				$free = $this->storage->free_space($path);
92
-				$quotaFree = max($this->quota - $used, 0);
93
-				// if free space is known
94
-				if ($free >= 0) {
95
-					$free = min($free, $quotaFree);
96
-				} else {
97
-					$free = $quotaFree;
98
-				}
99
-				return $free;
100
-			}
101
-		}
102
-	}
103
-
104
-	/**
105
-	 * see http://php.net/manual/en/function.file_put_contents.php
106
-	 *
107
-	 * @param string $path
108
-	 * @param string $data
109
-	 * @return bool
110
-	 */
111
-	public function file_put_contents($path, $data) {
112
-		$free = $this->free_space('');
113
-		if ($free < 0 or strlen($data) < $free) {
114
-			return $this->storage->file_put_contents($path, $data);
115
-		} else {
116
-			return false;
117
-		}
118
-	}
119
-
120
-	/**
121
-	 * see http://php.net/manual/en/function.copy.php
122
-	 *
123
-	 * @param string $source
124
-	 * @param string $target
125
-	 * @return bool
126
-	 */
127
-	public function copy($source, $target) {
128
-		$free = $this->free_space('');
129
-		if ($free < 0 or $this->getSize($source) < $free) {
130
-			return $this->storage->copy($source, $target);
131
-		} else {
132
-			return false;
133
-		}
134
-	}
135
-
136
-	/**
137
-	 * see http://php.net/manual/en/function.fopen.php
138
-	 *
139
-	 * @param string $path
140
-	 * @param string $mode
141
-	 * @return resource
142
-	 */
143
-	public function fopen($path, $mode) {
144
-		$source = $this->storage->fopen($path, $mode);
145
-
146
-		// don't apply quota for part files
147
-		if (!$this->isPartFile($path)) {
148
-			$free = $this->free_space('');
149
-			if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
150
-				// only apply quota for files, not metadata, trash or others
151
-				if (strpos(ltrim($path, '/'), 'files/') === 0) {
152
-					return \OC\Files\Stream\Quota::wrap($source, $free);
153
-				}
154
-			}
155
-		}
156
-		return $source;
157
-	}
158
-
159
-	/**
160
-	 * Checks whether the given path is a part file
161
-	 *
162
-	 * @param string $path Path that may identify a .part file
163
-	 * @return string File path without .part extension
164
-	 * @note this is needed for reusing keys
165
-	 */
166
-	private function isPartFile($path) {
167
-		$extension = pathinfo($path, PATHINFO_EXTENSION);
168
-
169
-		return ($extension === 'part');
170
-	}
171
-
172
-	/**
173
-	 * @param \OCP\Files\Storage $sourceStorage
174
-	 * @param string $sourceInternalPath
175
-	 * @param string $targetInternalPath
176
-	 * @return bool
177
-	 */
178
-	public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
179
-		$free = $this->free_space('');
180
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
181
-			return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
182
-		} else {
183
-			return false;
184
-		}
185
-	}
186
-
187
-	/**
188
-	 * @param \OCP\Files\Storage $sourceStorage
189
-	 * @param string $sourceInternalPath
190
-	 * @param string $targetInternalPath
191
-	 * @return bool
192
-	 */
193
-	public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
194
-		$free = $this->free_space('');
195
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
196
-			return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
197
-		} else {
198
-			return false;
199
-		}
200
-	}
33
+    /**
34
+     * @var int $quota
35
+     */
36
+    protected $quota;
37
+
38
+    /**
39
+     * @var string $sizeRoot
40
+     */
41
+    protected $sizeRoot;
42
+
43
+    /**
44
+     * @param array $parameters
45
+     */
46
+    public function __construct($parameters) {
47
+        $this->storage = $parameters['storage'];
48
+        $this->quota = $parameters['quota'];
49
+        $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
50
+    }
51
+
52
+    /**
53
+     * @return int quota value
54
+     */
55
+    public function getQuota() {
56
+        return $this->quota;
57
+    }
58
+
59
+    /**
60
+     * @param string $path
61
+     * @param \OC\Files\Storage\Storage $storage
62
+     */
63
+    protected function getSize($path, $storage = null) {
64
+        if (is_null($storage)) {
65
+            $cache = $this->getCache();
66
+        } else {
67
+            $cache = $storage->getCache();
68
+        }
69
+        $data = $cache->get($path);
70
+        if ($data instanceof ICacheEntry and isset($data['size'])) {
71
+            return $data['size'];
72
+        } else {
73
+            return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
74
+        }
75
+    }
76
+
77
+    /**
78
+     * Get free space as limited by the quota
79
+     *
80
+     * @param string $path
81
+     * @return int
82
+     */
83
+    public function free_space($path) {
84
+        if ($this->quota < 0) {
85
+            return $this->storage->free_space($path);
86
+        } else {
87
+            $used = $this->getSize($this->sizeRoot);
88
+            if ($used < 0) {
89
+                return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
90
+            } else {
91
+                $free = $this->storage->free_space($path);
92
+                $quotaFree = max($this->quota - $used, 0);
93
+                // if free space is known
94
+                if ($free >= 0) {
95
+                    $free = min($free, $quotaFree);
96
+                } else {
97
+                    $free = $quotaFree;
98
+                }
99
+                return $free;
100
+            }
101
+        }
102
+    }
103
+
104
+    /**
105
+     * see http://php.net/manual/en/function.file_put_contents.php
106
+     *
107
+     * @param string $path
108
+     * @param string $data
109
+     * @return bool
110
+     */
111
+    public function file_put_contents($path, $data) {
112
+        $free = $this->free_space('');
113
+        if ($free < 0 or strlen($data) < $free) {
114
+            return $this->storage->file_put_contents($path, $data);
115
+        } else {
116
+            return false;
117
+        }
118
+    }
119
+
120
+    /**
121
+     * see http://php.net/manual/en/function.copy.php
122
+     *
123
+     * @param string $source
124
+     * @param string $target
125
+     * @return bool
126
+     */
127
+    public function copy($source, $target) {
128
+        $free = $this->free_space('');
129
+        if ($free < 0 or $this->getSize($source) < $free) {
130
+            return $this->storage->copy($source, $target);
131
+        } else {
132
+            return false;
133
+        }
134
+    }
135
+
136
+    /**
137
+     * see http://php.net/manual/en/function.fopen.php
138
+     *
139
+     * @param string $path
140
+     * @param string $mode
141
+     * @return resource
142
+     */
143
+    public function fopen($path, $mode) {
144
+        $source = $this->storage->fopen($path, $mode);
145
+
146
+        // don't apply quota for part files
147
+        if (!$this->isPartFile($path)) {
148
+            $free = $this->free_space('');
149
+            if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
150
+                // only apply quota for files, not metadata, trash or others
151
+                if (strpos(ltrim($path, '/'), 'files/') === 0) {
152
+                    return \OC\Files\Stream\Quota::wrap($source, $free);
153
+                }
154
+            }
155
+        }
156
+        return $source;
157
+    }
158
+
159
+    /**
160
+     * Checks whether the given path is a part file
161
+     *
162
+     * @param string $path Path that may identify a .part file
163
+     * @return string File path without .part extension
164
+     * @note this is needed for reusing keys
165
+     */
166
+    private function isPartFile($path) {
167
+        $extension = pathinfo($path, PATHINFO_EXTENSION);
168
+
169
+        return ($extension === 'part');
170
+    }
171
+
172
+    /**
173
+     * @param \OCP\Files\Storage $sourceStorage
174
+     * @param string $sourceInternalPath
175
+     * @param string $targetInternalPath
176
+     * @return bool
177
+     */
178
+    public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
179
+        $free = $this->free_space('');
180
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
181
+            return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
182
+        } else {
183
+            return false;
184
+        }
185
+    }
186
+
187
+    /**
188
+     * @param \OCP\Files\Storage $sourceStorage
189
+     * @param string $sourceInternalPath
190
+     * @param string $targetInternalPath
191
+     * @return bool
192
+     */
193
+    public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
194
+        $free = $this->free_space('');
195
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
196
+            return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
197
+        } else {
198
+            return false;
199
+        }
200
+    }
201 201
 }
Please login to merge, or discard this patch.
lib/private/Files/Stream/StaticStream.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -144,6 +144,9 @@
 block discarded – undo
144 144
 		return true;
145 145
 	}
146 146
 
147
+	/**
148
+	 * @param string $path
149
+	 */
147 150
 	public function url_stat($path) {
148 151
 		if (isset(self::$data[$path])) {
149 152
 			$size = strlen(self::$data[$path]);
Please login to merge, or discard this patch.
Indentation   +144 added lines, -144 removed lines patch added patch discarded remove patch
@@ -24,148 +24,148 @@
 block discarded – undo
24 24
 namespace OC\Files\Stream;
25 25
 
26 26
 class StaticStream {
27
-	const MODE_FILE = 0100000;
28
-
29
-	public $context;
30
-	protected static $data = array();
31
-
32
-	protected $path = '';
33
-	protected $pointer = 0;
34
-	protected $writable = false;
35
-
36
-	public function stream_close() {
37
-	}
38
-
39
-	public function stream_eof() {
40
-		return $this->pointer >= strlen(self::$data[$this->path]);
41
-	}
42
-
43
-	public function stream_flush() {
44
-	}
45
-
46
-	public static function clear() {
47
-		self::$data = array();
48
-	}
49
-
50
-	public function stream_open($path, $mode, $options, &$opened_path) {
51
-		switch ($mode[0]) {
52
-			case 'r':
53
-				if (!isset(self::$data[$path])) return false;
54
-				$this->path = $path;
55
-				$this->writable = isset($mode[1]) && $mode[1] == '+';
56
-				break;
57
-			case 'w':
58
-				self::$data[$path] = '';
59
-				$this->path = $path;
60
-				$this->writable = true;
61
-				break;
62
-			case 'a':
63
-				if (!isset(self::$data[$path])) self::$data[$path] = '';
64
-				$this->path = $path;
65
-				$this->writable = true;
66
-				$this->pointer = strlen(self::$data[$path]);
67
-				break;
68
-			case 'x':
69
-				if (isset(self::$data[$path])) return false;
70
-				$this->path = $path;
71
-				$this->writable = true;
72
-				break;
73
-			case 'c':
74
-				if (!isset(self::$data[$path])) self::$data[$path] = '';
75
-				$this->path = $path;
76
-				$this->writable = true;
77
-				break;
78
-			default:
79
-				return false;
80
-		}
81
-		$opened_path = $this->path;
82
-		return true;
83
-	}
84
-
85
-	public function stream_read($count) {
86
-		$bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count);
87
-		$data = substr(self::$data[$this->path], $this->pointer, $bytes);
88
-		$this->pointer += $bytes;
89
-		return $data;
90
-	}
91
-
92
-	public function stream_seek($offset, $whence = SEEK_SET) {
93
-		$len = strlen(self::$data[$this->path]);
94
-		switch ($whence) {
95
-			case SEEK_SET:
96
-				if ($offset <= $len) {
97
-					$this->pointer = $offset;
98
-					return true;
99
-				}
100
-				break;
101
-			case SEEK_CUR:
102
-				if ($this->pointer + $offset <= $len) {
103
-					$this->pointer += $offset;
104
-					return true;
105
-				}
106
-				break;
107
-			case SEEK_END:
108
-				if ($len + $offset <= $len) {
109
-					$this->pointer = $len + $offset;
110
-					return true;
111
-				}
112
-				break;
113
-		}
114
-		return false;
115
-	}
116
-
117
-	public function stream_stat() {
118
-		return $this->url_stat($this->path);
119
-	}
120
-
121
-	public function stream_tell() {
122
-		return $this->pointer;
123
-	}
124
-
125
-	public function stream_write($data) {
126
-		if (!$this->writable) return 0;
127
-		$size = strlen($data);
128
-		if ($this->stream_eof()) {
129
-			self::$data[$this->path] .= $data;
130
-		} else {
131
-			self::$data[$this->path] = substr_replace(
132
-				self::$data[$this->path],
133
-				$data,
134
-				$this->pointer
135
-			);
136
-		}
137
-		$this->pointer += $size;
138
-		return $size;
139
-	}
140
-
141
-	public function unlink($path) {
142
-		if (isset(self::$data[$path])) {
143
-			unset(self::$data[$path]);
144
-		}
145
-		return true;
146
-	}
147
-
148
-	public function url_stat($path) {
149
-		if (isset(self::$data[$path])) {
150
-			$size = strlen(self::$data[$path]);
151
-			$time = time();
152
-			$data = array(
153
-				'dev' => 0,
154
-				'ino' => 0,
155
-				'mode' => self::MODE_FILE | 0777,
156
-				'nlink' => 1,
157
-				'uid' => 0,
158
-				'gid' => 0,
159
-				'rdev' => '',
160
-				'size' => $size,
161
-				'atime' => $time,
162
-				'mtime' => $time,
163
-				'ctime' => $time,
164
-				'blksize' => -1,
165
-				'blocks' => -1,
166
-			);
167
-			return array_values($data) + $data;
168
-		}
169
-		return false;
170
-	}
27
+    const MODE_FILE = 0100000;
28
+
29
+    public $context;
30
+    protected static $data = array();
31
+
32
+    protected $path = '';
33
+    protected $pointer = 0;
34
+    protected $writable = false;
35
+
36
+    public function stream_close() {
37
+    }
38
+
39
+    public function stream_eof() {
40
+        return $this->pointer >= strlen(self::$data[$this->path]);
41
+    }
42
+
43
+    public function stream_flush() {
44
+    }
45
+
46
+    public static function clear() {
47
+        self::$data = array();
48
+    }
49
+
50
+    public function stream_open($path, $mode, $options, &$opened_path) {
51
+        switch ($mode[0]) {
52
+            case 'r':
53
+                if (!isset(self::$data[$path])) return false;
54
+                $this->path = $path;
55
+                $this->writable = isset($mode[1]) && $mode[1] == '+';
56
+                break;
57
+            case 'w':
58
+                self::$data[$path] = '';
59
+                $this->path = $path;
60
+                $this->writable = true;
61
+                break;
62
+            case 'a':
63
+                if (!isset(self::$data[$path])) self::$data[$path] = '';
64
+                $this->path = $path;
65
+                $this->writable = true;
66
+                $this->pointer = strlen(self::$data[$path]);
67
+                break;
68
+            case 'x':
69
+                if (isset(self::$data[$path])) return false;
70
+                $this->path = $path;
71
+                $this->writable = true;
72
+                break;
73
+            case 'c':
74
+                if (!isset(self::$data[$path])) self::$data[$path] = '';
75
+                $this->path = $path;
76
+                $this->writable = true;
77
+                break;
78
+            default:
79
+                return false;
80
+        }
81
+        $opened_path = $this->path;
82
+        return true;
83
+    }
84
+
85
+    public function stream_read($count) {
86
+        $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count);
87
+        $data = substr(self::$data[$this->path], $this->pointer, $bytes);
88
+        $this->pointer += $bytes;
89
+        return $data;
90
+    }
91
+
92
+    public function stream_seek($offset, $whence = SEEK_SET) {
93
+        $len = strlen(self::$data[$this->path]);
94
+        switch ($whence) {
95
+            case SEEK_SET:
96
+                if ($offset <= $len) {
97
+                    $this->pointer = $offset;
98
+                    return true;
99
+                }
100
+                break;
101
+            case SEEK_CUR:
102
+                if ($this->pointer + $offset <= $len) {
103
+                    $this->pointer += $offset;
104
+                    return true;
105
+                }
106
+                break;
107
+            case SEEK_END:
108
+                if ($len + $offset <= $len) {
109
+                    $this->pointer = $len + $offset;
110
+                    return true;
111
+                }
112
+                break;
113
+        }
114
+        return false;
115
+    }
116
+
117
+    public function stream_stat() {
118
+        return $this->url_stat($this->path);
119
+    }
120
+
121
+    public function stream_tell() {
122
+        return $this->pointer;
123
+    }
124
+
125
+    public function stream_write($data) {
126
+        if (!$this->writable) return 0;
127
+        $size = strlen($data);
128
+        if ($this->stream_eof()) {
129
+            self::$data[$this->path] .= $data;
130
+        } else {
131
+            self::$data[$this->path] = substr_replace(
132
+                self::$data[$this->path],
133
+                $data,
134
+                $this->pointer
135
+            );
136
+        }
137
+        $this->pointer += $size;
138
+        return $size;
139
+    }
140
+
141
+    public function unlink($path) {
142
+        if (isset(self::$data[$path])) {
143
+            unset(self::$data[$path]);
144
+        }
145
+        return true;
146
+    }
147
+
148
+    public function url_stat($path) {
149
+        if (isset(self::$data[$path])) {
150
+            $size = strlen(self::$data[$path]);
151
+            $time = time();
152
+            $data = array(
153
+                'dev' => 0,
154
+                'ino' => 0,
155
+                'mode' => self::MODE_FILE | 0777,
156
+                'nlink' => 1,
157
+                'uid' => 0,
158
+                'gid' => 0,
159
+                'rdev' => '',
160
+                'size' => $size,
161
+                'atime' => $time,
162
+                'mtime' => $time,
163
+                'ctime' => $time,
164
+                'blksize' => -1,
165
+                'blocks' => -1,
166
+            );
167
+            return array_values($data) + $data;
168
+        }
169
+        return false;
170
+    }
171 171
 }
Please login to merge, or discard this patch.
Braces   +15 added lines, -5 removed lines patch added patch discarded remove patch
@@ -50,7 +50,9 @@  discard block
 block discarded – undo
50 50
 	public function stream_open($path, $mode, $options, &$opened_path) {
51 51
 		switch ($mode[0]) {
52 52
 			case 'r':
53
-				if (!isset(self::$data[$path])) return false;
53
+				if (!isset(self::$data[$path])) {
54
+				    return false;
55
+				}
54 56
 				$this->path = $path;
55 57
 				$this->writable = isset($mode[1]) && $mode[1] == '+';
56 58
 				break;
@@ -60,18 +62,24 @@  discard block
 block discarded – undo
60 62
 				$this->writable = true;
61 63
 				break;
62 64
 			case 'a':
63
-				if (!isset(self::$data[$path])) self::$data[$path] = '';
65
+				if (!isset(self::$data[$path])) {
66
+				    self::$data[$path] = '';
67
+				}
64 68
 				$this->path = $path;
65 69
 				$this->writable = true;
66 70
 				$this->pointer = strlen(self::$data[$path]);
67 71
 				break;
68 72
 			case 'x':
69
-				if (isset(self::$data[$path])) return false;
73
+				if (isset(self::$data[$path])) {
74
+				    return false;
75
+				}
70 76
 				$this->path = $path;
71 77
 				$this->writable = true;
72 78
 				break;
73 79
 			case 'c':
74
-				if (!isset(self::$data[$path])) self::$data[$path] = '';
80
+				if (!isset(self::$data[$path])) {
81
+				    self::$data[$path] = '';
82
+				}
75 83
 				$this->path = $path;
76 84
 				$this->writable = true;
77 85
 				break;
@@ -123,7 +131,9 @@  discard block
 block discarded – undo
123 131
 	}
124 132
 
125 133
 	public function stream_write($data) {
126
-		if (!$this->writable) return 0;
134
+		if (!$this->writable) {
135
+		    return 0;
136
+		}
127 137
 		$size = strlen($data);
128 138
 		if ($this->stream_eof()) {
129 139
 			self::$data[$this->path] .= $data;
Please login to merge, or discard this patch.