arnaucube
arnaucube/openEventsPlatformAppPublic Self-hosted repository
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}