openEventsPlatformApp/plugins/cordova-plugin-file/src/ubuntu/file.cpp
plugins/cordova-plugin-file/src/ubuntu/file.cppRaw
1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15#include "file.h"
16
17#include <QApplication>
18
19namespace {
20 class FileError {
21 public:
22 static const QString kEncodingErr;
23 static const QString kTypeMismatchErr;
24 static const QString kNotFoundErr;
25 static const QString kSecurityErr;
26 static const QString kAbortErr;
27 static const QString kNotReadableErr;
28 static const QString kNoModificationAllowedErr;
29 static const QString kInvalidStateErr;
30 static const QString kSyntaxErr;
31 static const QString kInvalidModificationErr;
32 static const QString kQuotaExceededErr;
33 static const QString kPathExistsErr;
34 };
35
36 bool checkFileName(const QString &name) {
37 if (name.contains(":")){
38 return false;
39 }
40 return true;
41 }
42};
43
44const QString FileError::kEncodingErr("FileError.ENCODING_ERR");
45const QString FileError::kTypeMismatchErr("FileError.TYPE_MISMATCH_ERR");
46const QString FileError::kNotFoundErr("FileError.NOT_FOUND_ERR");
47const QString FileError::kSecurityErr("FileError.SECURITY_ERR");
48const QString FileError::kAbortErr("FileError.ABORT_ERR");
49const QString FileError::kNotReadableErr("FileError.NOT_READABLE_ERR");
50const QString FileError::kNoModificationAllowedErr("FileError.NO_MODIFICATION_ALLOWED_ERR");
51const QString FileError::kInvalidStateErr("FileError.INVALID_STATE_ERR");
52const QString FileError::kSyntaxErr("FileError.SYNTAX_ERR");
53const QString FileError::kInvalidModificationErr("FileError.INVALID_MODIFICATION_ERR");
54const QString FileError::kQuotaExceededErr("FileError.QUOTA_EXCEEDED_ERR");
55const QString FileError::kPathExistsErr("FileError.PATH_EXISTS_ERR");
56
57File::File(Cordova *cordova) :
58 CPlugin(cordova),
59 _persistentDir(QString("%1/.local/share/%2/persistent").arg(QDir::homePath()).arg(QCoreApplication::applicationName())) {
60 QDir::root().mkpath(_persistentDir.absolutePath());
61}
62
63QVariantMap File::file2map(const QFileInfo &fileInfo) {
64 QVariantMap res;
65
66 res.insert("name", fileInfo.fileName());
67 QPair<QString, QString> r = GetRelativePath(fileInfo);
68 res.insert("fullPath", QString("/") + r.second);
69 res.insert("filesystemName", r.first);
70
71 res.insert("nativeURL", QString("file://localhost") + fileInfo.absoluteFilePath());
72 res.insert("isDirectory", (int)fileInfo.isDir());
73 res.insert("isFile", (int)fileInfo.isFile());
74
75 return res;
76}
77
78QVariantMap File::dir2map(const QDir &dir) {
79 return file2map(QFileInfo(dir.absolutePath()));
80}
81
82QPair<QString, QString> File::GetRelativePath(const QFileInfo &fileInfo) {
83 QString fullPath = fileInfo.isDir() ? QDir::cleanPath(fileInfo.absoluteFilePath()) : fileInfo.absoluteFilePath();
84
85 QString relativePath1 = _persistentDir.relativeFilePath(fullPath);
86 QString relativePath2 = QDir::temp().relativeFilePath(fullPath);
87
88 if (!(relativePath1[0] != '.' || relativePath2[0] != '.')) {
89 if (relativePath1.size() > relativePath2.size()) {
90 return QPair<QString, QString>("temporary", relativePath2);
91 } else {
92 return QPair<QString, QString>("persistent", relativePath1);
93 }
94 }
95
96 if (relativePath1[0] != '.')
97 return QPair<QString, QString>("persistent", relativePath1);
98 return QPair<QString, QString>("temporary", relativePath2);
99}
100
101void File::requestFileSystem(int scId, int ecId, unsigned short type, unsigned long long size) {
102 QDir dir;
103
104 if (size >= 1000485760){
105 this->callback(ecId, FileError::kQuotaExceededErr);
106 return;
107 }
108
109 if (type == 0)
110 dir = QDir::temp();
111 else
112 dir = _persistentDir;
113
114 if (type > 1) {
115 this->callback(ecId, FileError::kSyntaxErr);
116 return;
117 } else {
118 QVariantMap res;
119 res.insert("root", dir2map(dir));
120 if (type == 0)
121 res.insert("name", "temporary");
122 else
123 res.insert("name", "persistent");
124
125 this->cb(scId, res);
126 }
127}
128
129QPair<bool, QFileInfo> File::resolveURI(int ecId, const QString &uri) {
130 QPair<bool, QFileInfo> result;
131
132 result.first = false;
133
134 QUrl url = QUrl::fromUserInput(uri);
135
136 if (url.scheme() == "file" && url.isValid()) {
137 result.first = true;
138 result.second = QFileInfo(url.path());
139 return result;
140 }
141
142 if (url.scheme() != "cdvfile") {
143 if (ecId)
144 this->callback(ecId, FileError::kTypeMismatchErr);
145 return result;
146 }
147
148 QString path = url.path().replace("//", "/");
149 //NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here.
150 if (path.contains(":") || !url.isValid()){
151 if (ecId)
152 this->callback(ecId, FileError::kEncodingErr);
153 return result;
154 }
155 if (!path.startsWith("/persistent/") && !path.startsWith("/temporary/")) {
156 if (ecId)
157 this->callback(ecId, FileError::kEncodingErr);
158 return result;
159 }
160
161 result.first = true;
162 if (path.startsWith("/persistent/")) {
163 QString relativePath = path.mid(QString("/persistent/").size());
164 result.second = QFileInfo(_persistentDir.filePath(relativePath));
165 } else {
166 QString relativePath = path.mid(QString("/temporary/").size());
167 result.second = QFileInfo(QDir::temp().filePath(relativePath));
168 }
169 return result;
170}
171
172QPair<bool, QFileInfo> File::resolveURI(const QString &uri) {
173 return resolveURI(0, uri);
174}
175
176
177void File::_getLocalFilesystemPath(int scId, int ecId, const QString& uri) {
178 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
179
180 if (!f1.first)
181 return;
182
183 this->cb(scId, f1.second.absoluteFilePath());
184}
185
186void File::resolveLocalFileSystemURI(int scId, int ecId, const QString &uri) {
187 if (uri[0] == '/' || uri[0] == '.') {
188 this->callback(ecId, FileError::kEncodingErr);
189 return;
190 }
191
192 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
193
194 if (!f1.first)
195 return;
196
197 QFileInfo fileInfo = f1.second;
198 if (!fileInfo.exists()) {
199 this->callback(ecId, FileError::kNotFoundErr);
200 return;
201 }
202
203 this->cb(scId, file2map(fileInfo));
204}
205
206void File::getFile(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) {
207 QPair<bool, QFileInfo> f1 = resolveURI(ecId, parentPath + "/" + rpath);
208 if (!f1.first)
209 return;
210
211 bool create = options.value("create").toBool();
212 bool exclusive = options.value("exclusive").toBool();
213 QFile file(f1.second.absoluteFilePath());
214
215 // if create is false and the path represents a directory, return error
216 QFileInfo fileInfo = f1.second;
217 if ((!create) && fileInfo.isDir()) {
218 this->callback(ecId, FileError::kTypeMismatchErr);
219 return;
220 }
221
222 // if file does exist, and create is true and exclusive is true, return error
223 if (file.exists()) {
224 if (create && exclusive) {
225 this->callback(ecId, FileError::kPathExistsErr);
226 return;
227 }
228 }
229 else {
230 // if file does not exist and create is false, return error
231 if (!create) {
232 this->callback(ecId, FileError::kNotFoundErr);
233 return;
234 }
235
236 file.open(QIODevice::WriteOnly);
237 file.close();
238
239 // Check if creation was successfull
240 if (!file.exists()) {
241 this->callback(ecId, FileError::kNoModificationAllowedErr);
242 return;
243 }
244 }
245
246 this->cb(scId, file2map(QFileInfo(file)));
247}
248
249void File::getDirectory(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) {
250 QPair<bool, QFileInfo> f1 = resolveURI(ecId, parentPath + "/" + rpath);
251 if (!f1.first)
252 return;
253
254 bool create = options.value("create").toBool();
255 bool exclusive = options.value("exclusive").toBool();
256 QDir dir(f1.second.absoluteFilePath());
257
258 QFileInfo &fileInfo = f1.second;
259 if ((!create) && fileInfo.isFile()) {
260 this->callback(ecId, FileError::kTypeMismatchErr);
261 return;
262 }
263
264 if (dir.exists()) {
265 if (create && exclusive) {
266 this->callback(ecId, FileError::kPathExistsErr);
267 return;
268 }
269 }
270 else {
271 if (!create) {
272 this->callback(ecId, FileError::kNotFoundErr);
273 return;
274 }
275
276 QString folderName = dir.dirName();
277 dir.cdUp();
278 dir.mkdir(folderName);
279 dir.cd(folderName);
280
281 if (!dir.exists()) {
282 this->callback(ecId, FileError::kNoModificationAllowedErr);
283 return;
284 }
285 }
286
287 this->cb(scId, dir2map(dir));
288}
289
290void File::removeRecursively(int scId, int ecId, const QString &uri) {
291 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
292
293 if (!f1.first)
294 return;
295
296 QDir dir(f1.second.absoluteFilePath());
297 if (File::rmDir(dir))
298 this->cb(scId);
299 else
300 this->callback(ecId, FileError::kNoModificationAllowedErr);
301}
302
303void File::write(int scId, int ecId, const QString &uri, const QString &_data, unsigned long long position, bool binary) {
304 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
305
306 if (!f1.first)
307 return;
308
309 QFile file(f1.second.absoluteFilePath());
310
311 file.open(QIODevice::WriteOnly);
312 file.close();
313
314 if (!file.exists()) {
315 this->callback(ecId, FileError::kNotFoundErr);
316 return;
317 }
318
319 QFileInfo fileInfo(file);
320 if (!file.open(QIODevice::ReadWrite)) {
321 this->callback(ecId, FileError::kNoModificationAllowedErr);
322 return;
323 }
324
325 if (!binary) {
326 QTextStream textStream(&file);
327 textStream.setCodec("UTF-8");
328 textStream.setAutoDetectUnicode(true);
329
330 if (!textStream.seek(position)) {
331 file.close();
332 fileInfo.refresh();
333
334 this->callback(ecId, FileError::kInvalidModificationErr);
335 return;
336 }
337
338 textStream << _data;
339 textStream.flush();
340 } else {
341 QByteArray data(_data.toUtf8());
342 if (!file.seek(position)) {
343 file.close();
344 fileInfo.refresh();
345
346 this->callback(ecId, FileError::kInvalidModificationErr);
347 return;
348 }
349
350 file.write(data.data(), data.length());
351 }
352
353 file.flush();
354 file.close();
355 fileInfo.refresh();
356
357 this->cb(scId, fileInfo.size() - position);
358}
359
360void File::truncate(int scId, int ecId, const QString &uri, unsigned long long size) {
361 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
362
363 if (!f1.first)
364 return;
365
366 QFile file(f1.second.absoluteFilePath());
367
368 if (!file.exists()) {
369 this->callback(ecId, FileError::kNotFoundErr);
370 return;
371 }
372
373 if (!file.resize(size)) {
374 this->callback(ecId, FileError::kNoModificationAllowedErr);
375 return;
376 }
377
378 this->cb(scId, size);
379}
380
381void File::getParent(int scId, int ecId, const QString &uri) {
382 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
383
384 if (!f1.first)
385 return;
386 QDir dir(f1.second.absoluteFilePath());
387
388 //can't cdup more than app's root
389 // Try to change into upper directory
390 if (dir != _persistentDir && dir != QDir::temp()){
391 if (!dir.cdUp()) {
392 this->callback(ecId, FileError::kNotFoundErr);
393 return;
394 }
395
396 }
397 this->cb(scId, dir2map(dir));
398}
399
400void File::remove(int scId, int ecId, const QString &uri) {
401 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
402 if (!f1.first)
403 return;
404
405 QFileInfo &fileInfo = f1.second;
406 //TODO: fix
407 if (!fileInfo.exists() || (fileInfo.absoluteFilePath() == _persistentDir.absolutePath()) || (QDir::temp() == fileInfo.absoluteFilePath())) {
408 this->callback(ecId, FileError::kNoModificationAllowedErr);
409 return;
410 }
411
412 if (fileInfo.isDir()) {
413 QDir dir(fileInfo.absoluteFilePath());
414 if (dir.rmdir(dir.absolutePath())) {
415 this->cb(scId);
416 return;
417 }
418 } else {
419 QFile file(fileInfo.absoluteFilePath());
420 if (file.remove()) {
421 this->cb(scId);
422 return;
423 }
424 }
425
426 this->callback(ecId, FileError::kInvalidModificationErr);
427}
428
429void File::getFileMetadata(int scId, int ecId, const QString &uri) {
430 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
431
432 if (!f1.first)
433 return;
434 QFileInfo &fileInfo = f1.second;
435
436 if (!fileInfo.exists()) {
437 this->callback(ecId, FileError::kNotFoundErr);
438 } else {
439 QMimeType mime = _db.mimeTypeForFile(fileInfo.fileName());
440
441 QString args = QString("{name: %1, fullPath: %2, type: %3, lastModifiedDate: new Date(%4), size: %5}")
442 .arg(CordovaInternal::format(fileInfo.fileName())).arg(CordovaInternal::format(fileInfo.absoluteFilePath()))
443 .arg(CordovaInternal::format(mime.name())).arg(fileInfo.lastModified().toMSecsSinceEpoch())
444 .arg(fileInfo.size());
445
446 this->callback(scId, args);
447 }
448}
449
450void File::getMetadata(int scId, int ecId, const QString &uri) {
451 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
452
453 if (!f1.first)
454 return;
455 QFileInfo &fileInfo = f1.second;
456
457 if (!fileInfo.exists())
458 this->callback(ecId, FileError::kNotFoundErr);
459 else {
460 QVariantMap obj;
461 obj.insert("modificationTime", fileInfo.lastModified().toMSecsSinceEpoch());
462 obj.insert("size", fileInfo.isDir() ? 0 : fileInfo.size());
463 this->cb(scId, obj);
464 }
465}
466
467void File::readEntries(int scId, int ecId, const QString &uri) {
468 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
469
470 if (!f1.first)
471 return;
472 QDir dir(f1.second.absoluteFilePath());
473 QString entriesList;
474
475 if (!dir.exists()) {
476 this->callback(ecId, FileError::kNotFoundErr);
477 return;
478 }
479
480 for (const QFileInfo &fileInfo: dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
481 entriesList += CordovaInternal::format(file2map(fileInfo)) + ",";
482 }
483 // Remove trailing comma
484 if (entriesList.size() > 0)
485 entriesList.remove(entriesList.size() - 1, 1);
486
487 entriesList = "new Array(" + entriesList + ")";
488
489 this->callback(scId, entriesList);
490}
491
492void File::readAsText(int scId, int ecId, const QString &uri, const QString &/*encoding*/, int sliceStart, int sliceEnd) {
493 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
494
495 if (!f1.first)
496 return;
497
498 QFile file(f1.second.absoluteFilePath());
499
500 if (!file.exists()) {
501 this->callback(ecId, FileError::kNotFoundErr);
502 return;
503 }
504
505 if (!file.open(QIODevice::ReadOnly)) {
506 this->callback(ecId, FileError::kNotReadableErr);
507 return;
508 }
509
510 QByteArray content = file.readAll();
511
512 if (sliceEnd == -1)
513 sliceEnd = content.size();
514 if (sliceEnd < 0) {
515 sliceEnd++;
516 sliceEnd = std::max(0, content.size() + sliceEnd);
517 }
518 if (sliceEnd > content.size())
519 sliceEnd = content.size();
520
521 if (sliceStart < 0)
522 sliceStart = std::max(0, content.size() + sliceStart);
523 if (sliceStart > content.size())
524 sliceStart = content.size();
525
526 if (sliceStart > sliceEnd)
527 sliceEnd = sliceStart;
528
529 //FIXME: encoding
530 content = content.mid(sliceStart, sliceEnd - sliceStart);
531
532 this->cb(scId, content);
533}
534
535void File::readAsArrayBuffer(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
536 const QString str2array("\
537 (function strToArray(str) { \
538 var res = new Uint8Array(str.length); \
539 for (var i = 0; i < str.length; i++) { \
540 res[i] = str.charCodeAt(i); \
541 } \
542 return res; \
543 })(\"%1\")");
544
545 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
546
547 if (!f1.first)
548 return;
549
550 QFile file(f1.second.absoluteFilePath());
551
552 if (!file.exists()) {
553 this->callback(ecId, FileError::kNotFoundErr);
554 return;
555 }
556
557 if (!file.open(QIODevice::ReadOnly)) {
558 this->callback(ecId, FileError::kNotReadableErr);
559 return;
560 }
561 QString res;
562 QByteArray content = file.readAll();
563
564 if (sliceEnd == -1)
565 sliceEnd = content.size();
566 if (sliceEnd < 0) {
567 sliceEnd++;
568 sliceEnd = std::max(0, content.size() + sliceEnd);
569 }
570 if (sliceEnd > content.size())
571 sliceEnd = content.size();
572
573 if (sliceStart < 0)
574 sliceStart = std::max(0, content.size() + sliceStart);
575 if (sliceStart > content.size())
576 sliceStart = content.size();
577
578 if (sliceStart > sliceEnd)
579 sliceEnd = sliceStart;
580
581 content = content.mid(sliceStart, sliceEnd - sliceStart);
582
583 res.reserve(content.length() * 6);
584 for (uchar c: content) {
585 res += "\\x";
586 res += QString::number(c, 16).rightJustified(2, '0').toUpper();
587 }
588
589 this->callback(scId, str2array.arg(res));
590}
591
592void File::readAsBinaryString(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
593 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
594
595 if (!f1.first)
596 return;
597
598 QFile file(f1.second.absoluteFilePath());
599
600 if (!file.exists()) {
601 this->callback(ecId, FileError::kNotFoundErr);
602 return;
603 }
604
605 if (!file.open(QIODevice::ReadOnly)) {
606 this->callback(ecId, FileError::kNotReadableErr);
607 return;
608 }
609 QString res;
610 QByteArray content = file.readAll();
611
612 if (sliceEnd == -1)
613 sliceEnd = content.size();
614 if (sliceEnd < 0) {
615 sliceEnd++;
616 sliceEnd = std::max(0, content.size() + sliceEnd);
617 }
618 if (sliceEnd > content.size())
619 sliceEnd = content.size();
620
621 if (sliceStart < 0)
622 sliceStart = std::max(0, content.size() + sliceStart);
623 if (sliceStart > content.size())
624 sliceStart = content.size();
625
626 if (sliceStart > sliceEnd)
627 sliceEnd = sliceStart;
628
629 content = content.mid(sliceStart, sliceEnd - sliceStart);
630
631 res.reserve(content.length() * 6);
632 for (uchar c: content) {
633 res += "\\x";
634 res += QString::number(c, 16).rightJustified(2, '0').toUpper();
635 }
636 this->callback(scId, "\"" + res + "\"");
637}
638
639void File::readAsDataURL(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
640 QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
641
642 if (!f1.first)
643 return;
644
645 QFile file(f1.second.absoluteFilePath());
646 QFileInfo &fileInfo = f1.second;
647
648 if (!file.exists()) {
649 this->callback(ecId, FileError::kNotReadableErr);
650 return;
651 }
652
653 if (!file.open(QIODevice::ReadOnly)) {
654 this->callback(ecId, FileError::kNotReadableErr);
655 return;
656 }
657
658 QByteArray content = file.readAll();
659 QString contentType(_db.mimeTypeForFile(fileInfo.fileName()).name());
660
661 if (sliceEnd == -1)
662 sliceEnd = content.size();
663 if (sliceEnd < 0) {
664 sliceEnd++;
665 sliceEnd = std::max(0, content.size() + sliceEnd);
666 }
667 if (sliceEnd > content.size())
668 sliceEnd = content.size();
669
670 if (sliceStart < 0)
671 sliceStart = std::max(0, content.size() + sliceStart);
672 if (sliceStart > content.size())
673 sliceStart = content.size();
674
675 if (sliceStart > sliceEnd)
676 sliceEnd = sliceStart;
677
678 content = content.mid(sliceStart, sliceEnd - sliceStart);
679
680 this->cb(scId, QString("data:%1;base64,").arg(contentType) + content.toBase64());
681}
682
683bool File::rmDir(const QDir &dir) {
684 if (dir == _persistentDir || dir == QDir::temp()) {//can't remove root dir
685 return false;
686 }
687 bool result = true;
688 if (dir.exists()) {
689 // Iterate over entries and remove them
690 Q_FOREACH(const QFileInfo &fileInfo, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
691 if (fileInfo.isDir()) {
692 result = rmDir(fileInfo.absoluteFilePath());
693 }
694 else {
695 result = QFile::remove(fileInfo.absoluteFilePath());
696 }
697
698 if (!result) {
699 return result;
700 }
701 }
702
703 // Finally remove the current dir
704 return dir.rmdir(dir.absolutePath());
705 }
706 return result;
707}
708
709bool File::copyFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
710 QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
711 QPair<bool, QFileInfo> sourceFile = resolveURI(ecId, sourceUri);
712
713 if (!destDir.first || !sourceFile.first)
714 return false;
715
716 if (!checkFileName(newName)) {
717 this->callback(ecId, FileError::kEncodingErr);
718 return false;
719 }
720
721 if (destDir.second.isFile()) {
722 this->callback(ecId, FileError::kInvalidModificationErr);
723 return false;
724 }
725
726 if (!destDir.second.isDir()) {
727 this->callback(ecId, FileError::kNotFoundErr);
728 return false;
729 }
730
731 QFileInfo &fileInfo = sourceFile.second;
732 QString fileName((newName.isEmpty()) ? fileInfo.fileName() : newName);
733 QString destinationFile(QDir(destDir.second.absoluteFilePath()).filePath(fileName));
734 if (QFile::copy(fileInfo.absoluteFilePath(), destinationFile)){
735 this->cb(scId, file2map(QFileInfo(destinationFile)));
736 return true;
737 }
738 this->callback(ecId, FileError::kInvalidModificationErr);
739 return false;
740}
741
742void File::copyDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
743 QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
744 QPair<bool, QFileInfo> sourceDir = resolveURI(ecId, sourceUri);
745
746 if (!destDir.first || !sourceDir.first)
747 return;
748 if (!checkFileName(newName)) {
749 this->callback(ecId, FileError::kEncodingErr);
750 return;
751 }
752
753 QString targetName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName);
754 QString target(QDir(destDir.second.absoluteFilePath()).filePath(targetName));
755
756 if (QFileInfo(target).isFile()){
757 this->callback(ecId, FileError::kInvalidModificationErr);
758 return;
759 }
760
761 // check: copy directory into itself
762 if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){
763 this->callback(ecId, FileError::kInvalidModificationErr);
764 return;
765 }
766
767 if (!QDir(target).exists()){
768 QDir(destDir.second.absoluteFilePath()).mkdir(target);;
769 } else{
770 this->callback(ecId, FileError::kInvalidModificationErr);
771 return;
772 }
773
774 if (copyFolder(sourceDir.second.absoluteFilePath(), target)){
775 this->cb(scId, dir2map(QDir(target)));
776 return;
777 }
778 this->callback(ecId, FileError::kInvalidModificationErr);
779 return;
780}
781
782void File::copyTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) {
783 QPair<bool, QFileInfo> f1 = resolveURI(ecId, source);
784
785 if (!f1.first)
786 return;
787
788 if (f1.second.isDir())
789 copyDir(scId, ecId, source, destinationDir, newName);
790 else
791 copyFile(scId, ecId, source, destinationDir, newName);
792}
793
794void File::moveFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
795 QPair<bool, QFileInfo> sourceFile = resolveURI(ecId, sourceUri);
796 QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
797
798 if (!destDir.first || !sourceFile.first)
799 return;
800 if (!checkFileName(newName)) {
801 this->callback(ecId, FileError::kEncodingErr);
802 return;
803 }
804
805 QString fileName = ((newName.isEmpty()) ? sourceFile.second.fileName() : newName);
806 QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName);
807
808 if (sourceFile.second == QFileInfo(target)) {
809 this->callback(ecId, FileError::kInvalidModificationErr);
810 return;
811 }
812
813 if (!destDir.second.exists()) {
814 this->callback(ecId, FileError::kNotFoundErr);
815 return;
816 }
817 if (!destDir.second.isDir()){
818 this->callback(ecId, FileError::kInvalidModificationErr);
819 return;
820 }
821
822 if (QFileInfo(target).exists()) {
823 if (!QFile::remove(target)) {
824 this->callback(ecId, FileError::kInvalidModificationErr);
825 return;
826 }
827 }
828
829 QFile::rename(sourceFile.second.absoluteFilePath(), target);
830 this->cb(scId, file2map(QFileInfo(target)));
831}
832
833void File::moveDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName){
834 QPair<bool, QFileInfo> sourceDir = resolveURI(ecId, sourceUri);
835 QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
836
837 if (!destDir.first || !sourceDir.first)
838 return;
839 if (!checkFileName(newName)) {
840 this->callback(ecId, FileError::kEncodingErr);
841 return;
842 }
843
844 QString fileName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName);
845 QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName);
846
847 if (!destDir.second.exists()){
848 this->callback(ecId, FileError::kNotFoundErr);
849 return;
850 }
851
852 if (destDir.second.isFile()){
853 this->callback(ecId, FileError::kInvalidModificationErr);
854 return;
855 }
856
857 // check: copy directory into itself
858 if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){
859 this->callback(ecId, FileError::kInvalidModificationErr);
860 return;
861 }
862
863 if (QFileInfo(target).exists() && !QDir(destDir.second.absoluteFilePath()).rmdir(fileName)) {
864 this->callback(ecId, FileError::kInvalidModificationErr);
865 return;
866 }
867
868 if (copyFolder(sourceDir.second.absoluteFilePath(), target)) {
869 rmDir(sourceDir.second.absoluteFilePath());
870 this->cb(scId, file2map(QFileInfo(target)));
871 } else {
872 this->callback(ecId, FileError::kNoModificationAllowedErr);
873 }
874}
875
876void File::moveTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) {
877 QPair<bool, QFileInfo> f1 = resolveURI(ecId, source);
878
879 if (!f1.first)
880 return;
881
882 if (f1.second.isDir())
883 moveDir(scId, ecId, source, destinationDir, newName);
884 else
885 moveFile(scId, ecId, source, destinationDir, newName);
886}
887
888bool File::copyFolder(const QString& sourceFolder, const QString& destFolder) {
889 QDir sourceDir(sourceFolder);
890 if (!sourceDir.exists())
891 return false;
892 QDir destDir(destFolder);
893 if (!destDir.exists()){
894 destDir.mkdir(destFolder);
895 }
896 QStringList files = sourceDir.entryList(QDir::Files);
897 for (int i = 0; i< files.count(); i++)
898 {
899 QString srcName = sourceFolder + "/" + files[i];
900 QString destName = destFolder + "/" + files[i];
901 QFile::copy(srcName, destName);
902 }
903 files.clear();
904 files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
905 for (int i = 0; i< files.count(); i++)
906 {
907 QString srcName = sourceFolder + "/" + files[i];
908 QString destName = destFolder + "/" + files[i];
909 copyFolder(srcName, destName);
910 }
911 return true;
912}