blob: 395ab2ddd103d1b058e61c475b0bd83035b8c0f3 [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "file.h"
#include <QApplication>
namespace {
class FileError {
public:
static const QString kEncodingErr;
static const QString kTypeMismatchErr;
static const QString kNotFoundErr;
static const QString kSecurityErr;
static const QString kAbortErr;
static const QString kNotReadableErr;
static const QString kNoModificationAllowedErr;
static const QString kInvalidStateErr;
static const QString kSyntaxErr;
static const QString kInvalidModificationErr;
static const QString kQuotaExceededErr;
static const QString kPathExistsErr;
};
bool checkFileName(const QString &name) {
if (name.contains(":")){
return false;
}
return true;
}
};
const QString FileError::kEncodingErr("FileError.ENCODING_ERR");
const QString FileError::kTypeMismatchErr("FileError.TYPE_MISMATCH_ERR");
const QString FileError::kNotFoundErr("FileError.NOT_FOUND_ERR");
const QString FileError::kSecurityErr("FileError.SECURITY_ERR");
const QString FileError::kAbortErr("FileError.ABORT_ERR");
const QString FileError::kNotReadableErr("FileError.NOT_READABLE_ERR");
const QString FileError::kNoModificationAllowedErr("FileError.NO_MODIFICATION_ALLOWED_ERR");
const QString FileError::kInvalidStateErr("FileError.INVALID_STATE_ERR");
const QString FileError::kSyntaxErr("FileError.SYNTAX_ERR");
const QString FileError::kInvalidModificationErr("FileError.INVALID_MODIFICATION_ERR");
const QString FileError::kQuotaExceededErr("FileError.QUOTA_EXCEEDED_ERR");
const QString FileError::kPathExistsErr("FileError.PATH_EXISTS_ERR");
File::File(Cordova *cordova) :
CPlugin(cordova),
_persistentDir(QString("%1/.local/share/%2/persistent").arg(QDir::homePath()).arg(QCoreApplication::applicationName())) {
QDir::root().mkpath(_persistentDir.absolutePath());
}
QVariantMap File::file2map(const QFileInfo &fileInfo) {
QVariantMap res;
res.insert("name", fileInfo.fileName());
QPair<QString, QString> r = GetRelativePath(fileInfo);
res.insert("fullPath", QString("/") + r.second);
res.insert("filesystemName", r.first);
res.insert("nativeURL", QString("file://localhost") + fileInfo.absoluteFilePath());
res.insert("isDirectory", (int)fileInfo.isDir());
res.insert("isFile", (int)fileInfo.isFile());
return res;
}
QVariantMap File::dir2map(const QDir &dir) {
return file2map(QFileInfo(dir.absolutePath()));
}
QPair<QString, QString> File::GetRelativePath(const QFileInfo &fileInfo) {
QString fullPath = fileInfo.isDir() ? QDir::cleanPath(fileInfo.absoluteFilePath()) : fileInfo.absoluteFilePath();
QString relativePath1 = _persistentDir.relativeFilePath(fullPath);
QString relativePath2 = QDir::temp().relativeFilePath(fullPath);
if (!(relativePath1[0] != '.' || relativePath2[0] != '.')) {
if (relativePath1.size() > relativePath2.size()) {
return QPair<QString, QString>("temporary", relativePath2);
} else {
return QPair<QString, QString>("persistent", relativePath1);
}
}
if (relativePath1[0] != '.')
return QPair<QString, QString>("persistent", relativePath1);
return QPair<QString, QString>("temporary", relativePath2);
}
void File::requestFileSystem(int scId, int ecId, unsigned short type, unsigned long long size) {
QDir dir;
if (size >= 1000485760){
this->callback(ecId, FileError::kQuotaExceededErr);
return;
}
if (type == 0)
dir = QDir::temp();
else
dir = _persistentDir;
if (type > 1) {
this->callback(ecId, FileError::kSyntaxErr);
return;
} else {
QVariantMap res;
res.insert("root", dir2map(dir));
if (type == 0)
res.insert("name", "temporary");
else
res.insert("name", "persistent");
this->cb(scId, res);
}
}
QPair<bool, QFileInfo> File::resolveURI(int ecId, const QString &uri) {
QPair<bool, QFileInfo> result;
result.first = false;
QUrl url = QUrl::fromUserInput(uri);
if (url.scheme() == "file" && url.isValid()) {
result.first = true;
result.second = QFileInfo(url.path());
return result;
}
if (url.scheme() != "cdvfile") {
if (ecId)
this->callback(ecId, FileError::kTypeMismatchErr);
return result;
}
QString path = url.path().replace("//", "/");
//NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here.
if (path.contains(":") || !url.isValid()){
if (ecId)
this->callback(ecId, FileError::kEncodingErr);
return result;
}
if (!path.startsWith("/persistent/") && !path.startsWith("/temporary/")) {
if (ecId)
this->callback(ecId, FileError::kEncodingErr);
return result;
}
result.first = true;
if (path.startsWith("/persistent/")) {
QString relativePath = path.mid(QString("/persistent/").size());
result.second = QFileInfo(_persistentDir.filePath(relativePath));
} else {
QString relativePath = path.mid(QString("/temporary/").size());
result.second = QFileInfo(QDir::temp().filePath(relativePath));
}
return result;
}
QPair<bool, QFileInfo> File::resolveURI(const QString &uri) {
return resolveURI(0, uri);
}
void File::_getLocalFilesystemPath(int scId, int ecId, const QString& uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
this->cb(scId, f1.second.absoluteFilePath());
}
void File::resolveLocalFileSystemURI(int scId, int ecId, const QString &uri) {
if (uri[0] == '/' || uri[0] == '.') {
this->callback(ecId, FileError::kEncodingErr);
return;
}
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFileInfo fileInfo = f1.second;
if (!fileInfo.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
this->cb(scId, file2map(fileInfo));
}
void File::getFile(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, parentPath + "/" + rpath);
if (!f1.first)
return;
bool create = options.value("create").toBool();
bool exclusive = options.value("exclusive").toBool();
QFile file(f1.second.absoluteFilePath());
// if create is false and the path represents a directory, return error
QFileInfo fileInfo = f1.second;
if ((!create) && fileInfo.isDir()) {
this->callback(ecId, FileError::kTypeMismatchErr);
return;
}
// if file does exist, and create is true and exclusive is true, return error
if (file.exists()) {
if (create && exclusive) {
this->callback(ecId, FileError::kPathExistsErr);
return;
}
}
else {
// if file does not exist and create is false, return error
if (!create) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
file.open(QIODevice::WriteOnly);
file.close();
// Check if creation was successfull
if (!file.exists()) {
this->callback(ecId, FileError::kNoModificationAllowedErr);
return;
}
}
this->cb(scId, file2map(QFileInfo(file)));
}
void File::getDirectory(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, parentPath + "/" + rpath);
if (!f1.first)
return;
bool create = options.value("create").toBool();
bool exclusive = options.value("exclusive").toBool();
QDir dir(f1.second.absoluteFilePath());
QFileInfo &fileInfo = f1.second;
if ((!create) && fileInfo.isFile()) {
this->callback(ecId, FileError::kTypeMismatchErr);
return;
}
if (dir.exists()) {
if (create && exclusive) {
this->callback(ecId, FileError::kPathExistsErr);
return;
}
}
else {
if (!create) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
QString folderName = dir.dirName();
dir.cdUp();
dir.mkdir(folderName);
dir.cd(folderName);
if (!dir.exists()) {
this->callback(ecId, FileError::kNoModificationAllowedErr);
return;
}
}
this->cb(scId, dir2map(dir));
}
void File::removeRecursively(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QDir dir(f1.second.absoluteFilePath());
if (File::rmDir(dir))
this->cb(scId);
else
this->callback(ecId, FileError::kNoModificationAllowedErr);
}
void File::write(int scId, int ecId, const QString &uri, const QString &_data, unsigned long long position, bool binary) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
file.open(QIODevice::WriteOnly);
file.close();
if (!file.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
QFileInfo fileInfo(file);
if (!file.open(QIODevice::ReadWrite)) {
this->callback(ecId, FileError::kNoModificationAllowedErr);
return;
}
if (!binary) {
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
textStream.setAutoDetectUnicode(true);
if (!textStream.seek(position)) {
file.close();
fileInfo.refresh();
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
textStream << _data;
textStream.flush();
} else {
QByteArray data(_data.toUtf8());
if (!file.seek(position)) {
file.close();
fileInfo.refresh();
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
file.write(data.data(), data.length());
}
file.flush();
file.close();
fileInfo.refresh();
this->cb(scId, fileInfo.size() - position);
}
void File::truncate(int scId, int ecId, const QString &uri, unsigned long long size) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
if (!file.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (!file.resize(size)) {
this->callback(ecId, FileError::kNoModificationAllowedErr);
return;
}
this->cb(scId, size);
}
void File::getParent(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QDir dir(f1.second.absoluteFilePath());
//can't cdup more than app's root
// Try to change into upper directory
if (dir != _persistentDir && dir != QDir::temp()){
if (!dir.cdUp()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
}
this->cb(scId, dir2map(dir));
}
void File::remove(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFileInfo &fileInfo = f1.second;
//TODO: fix
if (!fileInfo.exists() || (fileInfo.absoluteFilePath() == _persistentDir.absolutePath()) || (QDir::temp() == fileInfo.absoluteFilePath())) {
this->callback(ecId, FileError::kNoModificationAllowedErr);
return;
}
if (fileInfo.isDir()) {
QDir dir(fileInfo.absoluteFilePath());
if (dir.rmdir(dir.absolutePath())) {
this->cb(scId);
return;
}
} else {
QFile file(fileInfo.absoluteFilePath());
if (file.remove()) {
this->cb(scId);
return;
}
}
this->callback(ecId, FileError::kInvalidModificationErr);
}
void File::getFileMetadata(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFileInfo &fileInfo = f1.second;
if (!fileInfo.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
} else {
QMimeType mime = _db.mimeTypeForFile(fileInfo.fileName());
QString args = QString("{name: %1, fullPath: %2, type: %3, lastModifiedDate: new Date(%4), size: %5}")
.arg(CordovaInternal::format(fileInfo.fileName())).arg(CordovaInternal::format(fileInfo.absoluteFilePath()))
.arg(CordovaInternal::format(mime.name())).arg(fileInfo.lastModified().toMSecsSinceEpoch())
.arg(fileInfo.size());
this->callback(scId, args);
}
}
void File::getMetadata(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFileInfo &fileInfo = f1.second;
if (!fileInfo.exists())
this->callback(ecId, FileError::kNotFoundErr);
else {
QVariantMap obj;
obj.insert("modificationTime", fileInfo.lastModified().toMSecsSinceEpoch());
obj.insert("size", fileInfo.isDir() ? 0 : fileInfo.size());
this->cb(scId, obj);
}
}
void File::readEntries(int scId, int ecId, const QString &uri) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QDir dir(f1.second.absoluteFilePath());
QString entriesList;
if (!dir.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
for (const QFileInfo &fileInfo: dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
entriesList += CordovaInternal::format(file2map(fileInfo)) + ",";
}
// Remove trailing comma
if (entriesList.size() > 0)
entriesList.remove(entriesList.size() - 1, 1);
entriesList = "new Array(" + entriesList + ")";
this->callback(scId, entriesList);
}
void File::readAsText(int scId, int ecId, const QString &uri, const QString &/*encoding*/, int sliceStart, int sliceEnd) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
if (!file.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (!file.open(QIODevice::ReadOnly)) {
this->callback(ecId, FileError::kNotReadableErr);
return;
}
QByteArray content = file.readAll();
if (sliceEnd == -1)
sliceEnd = content.size();
if (sliceEnd < 0) {
sliceEnd++;
sliceEnd = std::max(0, content.size() + sliceEnd);
}
if (sliceEnd > content.size())
sliceEnd = content.size();
if (sliceStart < 0)
sliceStart = std::max(0, content.size() + sliceStart);
if (sliceStart > content.size())
sliceStart = content.size();
if (sliceStart > sliceEnd)
sliceEnd = sliceStart;
//FIXME: encoding
content = content.mid(sliceStart, sliceEnd - sliceStart);
this->cb(scId, content);
}
void File::readAsArrayBuffer(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
const QString str2array("\
(function strToArray(str) { \
var res = new Uint8Array(str.length); \
for (var i = 0; i < str.length; i++) { \
res[i] = str.charCodeAt(i); \
} \
return res; \
})(\"%1\")");
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
if (!file.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (!file.open(QIODevice::ReadOnly)) {
this->callback(ecId, FileError::kNotReadableErr);
return;
}
QString res;
QByteArray content = file.readAll();
if (sliceEnd == -1)
sliceEnd = content.size();
if (sliceEnd < 0) {
sliceEnd++;
sliceEnd = std::max(0, content.size() + sliceEnd);
}
if (sliceEnd > content.size())
sliceEnd = content.size();
if (sliceStart < 0)
sliceStart = std::max(0, content.size() + sliceStart);
if (sliceStart > content.size())
sliceStart = content.size();
if (sliceStart > sliceEnd)
sliceEnd = sliceStart;
content = content.mid(sliceStart, sliceEnd - sliceStart);
res.reserve(content.length() * 6);
for (uchar c: content) {
res += "\\x";
res += QString::number(c, 16).rightJustified(2, '0').toUpper();
}
this->callback(scId, str2array.arg(res));
}
void File::readAsBinaryString(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
if (!file.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (!file.open(QIODevice::ReadOnly)) {
this->callback(ecId, FileError::kNotReadableErr);
return;
}
QString res;
QByteArray content = file.readAll();
if (sliceEnd == -1)
sliceEnd = content.size();
if (sliceEnd < 0) {
sliceEnd++;
sliceEnd = std::max(0, content.size() + sliceEnd);
}
if (sliceEnd > content.size())
sliceEnd = content.size();
if (sliceStart < 0)
sliceStart = std::max(0, content.size() + sliceStart);
if (sliceStart > content.size())
sliceStart = content.size();
if (sliceStart > sliceEnd)
sliceEnd = sliceStart;
content = content.mid(sliceStart, sliceEnd - sliceStart);
res.reserve(content.length() * 6);
for (uchar c: content) {
res += "\\x";
res += QString::number(c, 16).rightJustified(2, '0').toUpper();
}
this->callback(scId, "\"" + res + "\"");
}
void File::readAsDataURL(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, uri);
if (!f1.first)
return;
QFile file(f1.second.absoluteFilePath());
QFileInfo &fileInfo = f1.second;
if (!file.exists()) {
this->callback(ecId, FileError::kNotReadableErr);
return;
}
if (!file.open(QIODevice::ReadOnly)) {
this->callback(ecId, FileError::kNotReadableErr);
return;
}
QByteArray content = file.readAll();
QString contentType(_db.mimeTypeForFile(fileInfo.fileName()).name());
if (sliceEnd == -1)
sliceEnd = content.size();
if (sliceEnd < 0) {
sliceEnd++;
sliceEnd = std::max(0, content.size() + sliceEnd);
}
if (sliceEnd > content.size())
sliceEnd = content.size();
if (sliceStart < 0)
sliceStart = std::max(0, content.size() + sliceStart);
if (sliceStart > content.size())
sliceStart = content.size();
if (sliceStart > sliceEnd)
sliceEnd = sliceStart;
content = content.mid(sliceStart, sliceEnd - sliceStart);
this->cb(scId, QString("data:%1;base64,").arg(contentType) + content.toBase64());
}
bool File::rmDir(const QDir &dir) {
if (dir == _persistentDir || dir == QDir::temp()) {//can't remove root dir
return false;
}
bool result = true;
if (dir.exists()) {
// Iterate over entries and remove them
Q_FOREACH(const QFileInfo &fileInfo, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
if (fileInfo.isDir()) {
result = rmDir(fileInfo.absoluteFilePath());
}
else {
result = QFile::remove(fileInfo.absoluteFilePath());
}
if (!result) {
return result;
}
}
// Finally remove the current dir
return dir.rmdir(dir.absolutePath());
}
return result;
}
bool File::copyFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
QPair<bool, QFileInfo> sourceFile = resolveURI(ecId, sourceUri);
if (!destDir.first || !sourceFile.first)
return false;
if (!checkFileName(newName)) {
this->callback(ecId, FileError::kEncodingErr);
return false;
}
if (destDir.second.isFile()) {
this->callback(ecId, FileError::kInvalidModificationErr);
return false;
}
if (!destDir.second.isDir()) {
this->callback(ecId, FileError::kNotFoundErr);
return false;
}
QFileInfo &fileInfo = sourceFile.second;
QString fileName((newName.isEmpty()) ? fileInfo.fileName() : newName);
QString destinationFile(QDir(destDir.second.absoluteFilePath()).filePath(fileName));
if (QFile::copy(fileInfo.absoluteFilePath(), destinationFile)){
this->cb(scId, file2map(QFileInfo(destinationFile)));
return true;
}
this->callback(ecId, FileError::kInvalidModificationErr);
return false;
}
void File::copyDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
QPair<bool, QFileInfo> sourceDir = resolveURI(ecId, sourceUri);
if (!destDir.first || !sourceDir.first)
return;
if (!checkFileName(newName)) {
this->callback(ecId, FileError::kEncodingErr);
return;
}
QString targetName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName);
QString target(QDir(destDir.second.absoluteFilePath()).filePath(targetName));
if (QFileInfo(target).isFile()){
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
// check: copy directory into itself
if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (!QDir(target).exists()){
QDir(destDir.second.absoluteFilePath()).mkdir(target);;
} else{
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (copyFolder(sourceDir.second.absoluteFilePath(), target)){
this->cb(scId, dir2map(QDir(target)));
return;
}
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
void File::copyTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, source);
if (!f1.first)
return;
if (f1.second.isDir())
copyDir(scId, ecId, source, destinationDir, newName);
else
copyFile(scId, ecId, source, destinationDir, newName);
}
void File::moveFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) {
QPair<bool, QFileInfo> sourceFile = resolveURI(ecId, sourceUri);
QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
if (!destDir.first || !sourceFile.first)
return;
if (!checkFileName(newName)) {
this->callback(ecId, FileError::kEncodingErr);
return;
}
QString fileName = ((newName.isEmpty()) ? sourceFile.second.fileName() : newName);
QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName);
if (sourceFile.second == QFileInfo(target)) {
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (!destDir.second.exists()) {
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (!destDir.second.isDir()){
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (QFileInfo(target).exists()) {
if (!QFile::remove(target)) {
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
}
QFile::rename(sourceFile.second.absoluteFilePath(), target);
this->cb(scId, file2map(QFileInfo(target)));
}
void File::moveDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName){
QPair<bool, QFileInfo> sourceDir = resolveURI(ecId, sourceUri);
QPair<bool, QFileInfo> destDir = resolveURI(ecId, destinationUri);
if (!destDir.first || !sourceDir.first)
return;
if (!checkFileName(newName)) {
this->callback(ecId, FileError::kEncodingErr);
return;
}
QString fileName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName);
QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName);
if (!destDir.second.exists()){
this->callback(ecId, FileError::kNotFoundErr);
return;
}
if (destDir.second.isFile()){
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
// check: copy directory into itself
if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (QFileInfo(target).exists() && !QDir(destDir.second.absoluteFilePath()).rmdir(fileName)) {
this->callback(ecId, FileError::kInvalidModificationErr);
return;
}
if (copyFolder(sourceDir.second.absoluteFilePath(), target)) {
rmDir(sourceDir.second.absoluteFilePath());
this->cb(scId, file2map(QFileInfo(target)));
} else {
this->callback(ecId, FileError::kNoModificationAllowedErr);
}
}
void File::moveTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) {
QPair<bool, QFileInfo> f1 = resolveURI(ecId, source);
if (!f1.first)
return;
if (f1.second.isDir())
moveDir(scId, ecId, source, destinationDir, newName);
else
moveFile(scId, ecId, source, destinationDir, newName);
}
bool File::copyFolder(const QString& sourceFolder, const QString& destFolder) {
QDir sourceDir(sourceFolder);
if (!sourceDir.exists())
return false;
QDir destDir(destFolder);
if (!destDir.exists()){
destDir.mkdir(destFolder);
}
QStringList files = sourceDir.entryList(QDir::Files);
for (int i = 0; i< files.count(); i++)
{
QString srcName = sourceFolder + "/" + files[i];
QString destName = destFolder + "/" + files[i];
QFile::copy(srcName, destName);
}
files.clear();
files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
for (int i = 0; i< files.count(); i++)
{
QString srcName = sourceFolder + "/" + files[i];
QString destName = destFolder + "/" + files[i];
copyFolder(srcName, destName);
}
return true;
}