bool PathHelper::isSymlink(QString path) {
    QFileInfo fileInfo(path);

    return fileInfo.isSymLink()
#ifdef Q_OS_MAC
           && !getSymlinkTarget(fileInfo.absoluteFilePath()).isEmpty()
#endif
            ;
}
QString PathHelper::getSymlinkTarget(QString symlink, int buffSize) {
    if (buffSize > INT_MAX)
        return "";

    char buff[buffSize];
    ssize_t len = readlink(symlink.toStdString().c_str(),
                           buff,
                           sizeof(buff)-1);
    if (len != -1) {
        buff[len] = '\0';

        return QString(buff);
    } else {
        if (errno == EFAULT)
            return getSymlinkTarget(symlink, buffSize * 10);
        else
            return "";
    }
}
Example #3
0
bool Global::copyDir(const QString src, const QString dst, const bool hidden) {
    if (!QDir().exists(src))
        return false;

    if (QDir().exists(dst))
        rmDir(dst);

    if (!QDir().mkpath(dst))
        return false;

    // Keep same folder permission
    preserveDirectoryPermission(src, dst); // Error isn't critical


    bool success = true;

    // Copy content of dir
    QStringList list;

    if (hidden)
        list = QDir(src).entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden, QDir::Name);
    else
        list = QDir(src).entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System, QDir::Name);


    foreach (const QString file, list) {
        QFileInfo info(src + "/" + file);

        if (info.isDir()) {
            if (!copyDir(src + "/" + file, dst + "/" + file, hidden))
                success = false;
        }
        else if (info.isSymLink()) {
            QString symlinkTarget = getSymlinkTarget(src + "/" + file);

            if (symlinkTarget.isEmpty() || !QFile::link(symlinkTarget, dst + "/" + file))
                success = false;
        }
        else {
            if (!QFile::copy(src + "/" + file, dst + "/" + file))
                success = false;
        }
    }
bool PathHelper::copyWholeDirectory_recursive(QString sourceDirPath, QString destDirPath, SymlinkHandlingModeEnum symlinkHandlingMode, bool isFailWhenContentCopyFails)
{
#ifdef ENABLE_PATH_MANAGER_LOGGING
    DLog(QString("copyWholeDirectory_recursive - sourceDir:%1 | destDir:%2").arg(sourceDirPath).arg(destDirPath));
#endif

    QDir sourceDir(sourceDirPath);
    if(!sourceDir.exists()) {
        WLogS << " ! The specified source path does not exists: " << sourceDirPath;
        return false;
    }

    QDir destDir(destDirPath);
    if(!destDir.exists())
    {
        if(!PathHelper::ensureDirectoryCreated(destDirPath)) {
            WLogS << " ! The specified destination path cannot be created: " << destDirPath;
            return false;
        }
    }

    if(!PathHelper::copyOnlyFilesOfDirectory(sourceDirPath, destDirPath, symlinkHandlingMode, true)) {
        if(isFailWhenContentCopyFails) {
            return false;
        }
    }

    // and get sub-directories as well
    QStringList dirs = sourceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden/* | QDir::NoSymLinks*/); // !!! No symlink folders allowed
    for(int i = 0; i < dirs.count(); i++)
    {
        QString srcDirFullPath = PathHelper::combineAndCleanPathes(sourceDirPath, dirs[i]);
        QString destDirFullPath = PathHelper::combineAndCleanPathes(destDirPath, dirs[i]);
        QFileInfo srcFInfo(srcDirFullPath);

        if(PathHelper::isSymlink(srcDirFullPath)) {
            DLog(QString(" - Symlink %1 found for target %2").arg(srcDirFullPath).arg(srcFInfo.symLinkTarget()));

            if(symlinkHandlingMode == SHM_UseAsFile) {
                // use as file

#ifdef Q_OS_WIN
                // copy it as a normal file
                if(!QFile::copy(srcDirFullPath, destDirFullPath)) {
                    WLog(QString(" ! Cannot copy the symlink-file from [%1] to [%2]").arg(srcDirFullPath).arg(destDirFullPath));
                    if(QFile::exists(destDirFullPath)) {
                        WLog("Dest file is already exists: ") << destDirFullPath;
                    }
                    return false;
                }
#endif


#ifdef Q_OS_MAC
//                if(QFileInfo(srcDirFullPath).symLinkTarget().isEmpty()) {
//                    WLog("Symlink found, but target is empty: ") << srcDirFullPath;
//                    continue;
//                }
                /////
                //QDir sourceDir(sourceDirPath);
                QString symlinkPath = getSymlinkTarget(QFileInfo(srcDirFullPath).absoluteFilePath());
                //sourceDir.relativeFilePath(srcFInfo.symLinkTarget());





                DLog(QString("Symlink created at path %1 with target %2").arg(destDirFullPath).arg(symlinkPath));

                /////

                if( !QFile::link(symlinkPath, destDirFullPath) ) {
                    WLog("Symlink cannot be created!");
                    if(isFailWhenContentCopyFails) {
                        WLog(" - Fail");
                        return false;
                    }
                }
#endif
            }
            else if(symlinkHandlingMode == SHM_UseAsTarget) {
                WLog("!!!!!!!! Not yet implemented! (will be ignored)");
            }
            else {
                DLog("Symlink handling mode: ignore.");
            }
        }
        else {
            if(!PathHelper::copyWholeDirectory_recursive(srcDirFullPath, destDirFullPath, symlinkHandlingMode, isFailWhenContentCopyFails)) {
                return false;
            }
        }
    }

    return true;
}
bool PathHelper::copyOnlyFilesOfDirectory(QString sourceDirPath, QString destDirPath, SymlinkHandlingModeEnum symlinkHandlingMode, bool isIgnoreDirectorySymlinks)
{
//    FLAG_FOR_REVIEW_WITH_HINT("Should copy symlink / shortcut files as well?? Temporarily removed / turned off.");

    QDir sourceDir(sourceDirPath);

    //
    // get everything, but handle only files and symlinks (pointing for other targets, like Drives)
    //

    QDir::Filters entryListFilters = QDir::NoDotAndDotDot | QDir::Files | QDir::Drives | QDir::Hidden | QDir::System;
    if(!isIgnoreDirectorySymlinks) {
        entryListFilters |= QDir::Dirs;
    }

    QStringList files = sourceDir.entryList(entryListFilters);
    for(int i = 0; i < files.count(); i++)
    {
        QString srcFullPath = PathHelper::combineAndCleanPathes(sourceDirPath, files[i]);
        QString destFullPath = PathHelper::combineAndCleanPathes(destDirPath, files[i]);

        // SYMLINKS

        // QFile cannot copy the file, when destName exists
        if(PathHelper::isSymlink(srcFullPath)) {
            // Symlink!
            DLogS << QString("Symlink found (%1) - target: (%2). Symlink-handling-mode: (%3) ").arg(srcFullPath).arg(QFileInfo(srcFullPath).symLinkTarget()).arg(symlinkHandlingMode);
//            WLog(QString("The file [%1] is a symlink to file [%2]").arg(srcName).arg( QFileInfo(srcName).symLinkTarget() ));

            if(symlinkHandlingMode == SHM_UseAsFile) {
                DLog(" - Symlink will be used as file, will be saved to path: ") << destFullPath;

#ifdef Q_OS_WIN
                // copy it as a normal file
                if(!QFile::copy(srcFullPath, destFullPath)) {
                    WLog(QString(" ! Cannot copy the symlink-file from [%1] to [%2]").arg(srcFullPath).arg(destFullPath));
                    return false;
                }
#endif

#ifdef Q_OS_MAC
//                if(QFileInfo(srcFullPath).symLinkTarget().isEmpty()) {
//                    WLog("Symlink found, but target is empty: ") << srcFullPath;
//                    continue;
//                }

//                QDir sourceDir(sourceDirPath);
                QString symlinkPath = getSymlinkTarget(QFileInfo(srcFullPath).absoluteFilePath());
                //sourceDir.relativeFilePath(QFileInfo(srcFullPath).symLinkTarget());

                DLog(QString("Symlink created at path %1 with target %2").arg(destFullPath).arg(symlinkPath));

                if( !QFile::link(symlinkPath, destFullPath) ) {
                    WLog("Symlink cannot be created!");
                    return false;
                }
#endif
            }
            else if(symlinkHandlingMode == SHM_UseAsTarget)
            {
                WLog(" - Symlink handling is set to 'UseAsTarget' - not yet implemented.");
//                QString linkTargetPath = QFileInfo(srcFullPath).symLinkTarget();
//                QFileInfo linkTargetFInfo(linkTargetPath);

//                if(linkTargetFInfo.isDir())
//                {
//                    // symlink target is a dir!
//                    DLog(" - Symlink target is a directory!");
//                    QDir linkTargetDir(linkTargetPath);
//                    if(!linkTargetDir.exists()) {
//                        WLog(" - Symlink target directory does NOT exists: ") << linkTargetPath;
//                    }
//                    QString destTargetDirPath = PathHelper::combineAndCleanPathes(destDirPath, linkTargetDir.dirName());
//                    DLog(" - Symlink dest target dir path: ") << destTargetDirPath;

//                    if(!PathHelper::copyWholeDirectory_recursive(srcFullPath, destTargetDirPath, symlinkHandlingMode, isFailWhenContentCopyFails)) {
//                        return false;
//                    }
//                }
//                else {
//                    DLog("Symlink target is a file: ") << linkTargetPath;
//                    QString destTargetFilePath = PathHelper::combineAndCleanPathes(destDirPath, linkTargetFInfo.fileName());
//                    DLog(" - Dest target File path: ") << destTargetFilePath;
//                    QFile::copy(linkTargetPath, destTargetFilePath);
//                }
            }
            else {
                DLog(" - Symlink ignored");
            }

        }

        else
        {
            // NOT symlink - handle only files
            if(QFileInfo(srcFullPath).isFile())
            {

                if(!QFile::copy(srcFullPath, destFullPath)) {
                    WLog(QString(" ! Cannot copy file from [%1] to [%2]").arg(srcFullPath).arg(destFullPath));
                    return false;
                }
                else {
#ifdef ENABLE_PATH_MANAGER_LOGGING
                    DLog(QString("Copy succeeded - file from [%1] to [%2]").arg(srcFullPath).arg(destFullPath));
#endif
                }
            }
            else {
                WLog("Not a symlink and not a file (will be ignored): ") << srcFullPath;
            }
        }
    }
    files.clear();

    return true;
}
bool PathHelper::copyWholeDirectory(QString sourceDirPath, QString destDirPath, bool isCopyOnlyContentOfSource, SymlinkHandlingModeEnum symlinkHandlingMode, bool isFailWhenContentCopyFails)
{
    if(!isCopyOnlyContentOfSource) {
        // copy the folder as well
        QDir sourceDir(sourceDirPath);
        QString newDestDirPath = PathHelper::combineAndCleanPathes(destDirPath, sourceDir.dirName());
        return PathHelper::copyWholeDirectory_recursive(sourceDirPath, newDestDirPath, symlinkHandlingMode, isFailWhenContentCopyFails);
    }

    // copy only the sub dirs
    QDir sourceDir(sourceDirPath);
    if(!sourceDir.exists()) {
        WLogS << " ! The specified source path does not exists: " << sourceDirPath;
        return false;
    }

    QStringList subDirs = sourceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden/*| QDir::NoSymLinks*/);
    if(subDirs.isEmpty()) {
#ifdef ENABLE_PATH_MANAGER_LOGGING
        DLogS << "The specified source directory is empty.";
#endif
        return true;
    }

    for(int i = 0; i < subDirs.count(); i++)
    {
        QString srcDirFullPath = PathHelper::combineAndCleanPathes(sourceDirPath, subDirs[i]);
        QString destDirFullPath = PathHelper::combineAndCleanPathes(destDirPath, subDirs[i]);
        QFileInfo srcFInfo(srcDirFullPath);

        if(PathHelper::isSymlink(srcDirFullPath)) {
            DLog(QString(" - (Dir)Symlink %1 found for target %2").arg(srcDirFullPath).arg(srcFInfo.symLinkTarget()));

            if(symlinkHandlingMode == SHM_UseAsFile) {
                // use as file

#ifdef Q_OS_WIN
                // copy it as a normal file
                if(!QFile::copy(srcDirFullPath, destDirFullPath)) {
                    WLog(QString(" ! Cannot copy the symlink-file from [%1] to [%2]").arg(srcDirFullPath).arg(destDirFullPath));
                    return false;
                }
#endif

#ifdef Q_OS_MAC
//                if(QFileInfo(srcDirFullPath).symLinkTarget().isEmpty()) {
//                    WLog("Symlink found, but target is empty: ") << srcDirFullPath;
//                    continue;
//                }

                /////
                //QDir sourceDir(sourceDirPath);
                QString symlinkPath = getSymlinkTarget(QFileInfo(srcDirFullPath).absoluteFilePath());
                //sourceDir.relativeFilePath(srcFInfo.symLinkTarget());

                DLog(QString("Symlink created at path %1 with target %2").arg(destDirFullPath).arg(symlinkPath));

                /////

                if( !QFile::link(symlinkPath, destDirFullPath) ) {
                    WLog("Symlink cannot be created!");
                    if(isFailWhenContentCopyFails) {
                        WLog(" - Fail");
                        return false;
                    }
                }
#endif
            }
            else if(symlinkHandlingMode == SHM_UseAsTarget) {
                WLog("!!!!!!!! Not yet implemented! (will be ignored)");
            }
            else {
                DLog("Symlink handling mode: ignore.");
            }
        }
        else {
            QString destName = PathHelper::combineAndCleanPathes(destDirPath, subDirs[i]);
            if(!PathHelper::copyWholeDirectory_recursive(srcDirFullPath, destName, symlinkHandlingMode, isFailWhenContentCopyFails)) {
                return false;
            }
        }
    }

    // also copy the files from sourceDirPath
    if(!PathHelper::copyOnlyFilesOfDirectory(sourceDirPath, destDirPath, symlinkHandlingMode, true)) {
        if(isFailWhenContentCopyFails) {
            return false;
        }
    }

    return true;
}