2022-05-27 02:48:54 +05:30
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
/*
|
2022-12-14 20:32:04 +05:30
|
|
|
* Prism Launcher - Minecraft Launcher
|
2022-05-27 02:48:54 +05:30
|
|
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
2022-12-14 20:32:04 +05:30
|
|
|
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
2023-02-09 12:12:13 +05:30
|
|
|
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
2022-05-27 02:48:54 +05:30
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 3.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* This file incorporates work covered by the following copyright and
|
|
|
|
* permission notice:
|
|
|
|
*
|
|
|
|
* Copyright 2013-2021 MultiMC Contributors
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2015-05-28 23:08:29 +05:30
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Exception.h"
|
2015-10-10 09:25:55 +05:30
|
|
|
#include "pathmatcher/IPathMatcher.h"
|
2015-05-28 23:08:29 +05:30
|
|
|
|
2023-02-08 14:05:03 +05:30
|
|
|
#include <system_error>
|
|
|
|
|
2015-10-05 05:17:27 +05:30
|
|
|
#include <QDir>
|
2015-10-10 09:25:55 +05:30
|
|
|
#include <QFlags>
|
2022-10-23 03:06:47 +05:30
|
|
|
#include <QObject>
|
2023-02-08 14:05:03 +05:30
|
|
|
#include <QThread>
|
|
|
|
#include <QLocalServer>
|
2015-09-05 22:16:57 +05:30
|
|
|
|
2022-07-30 23:12:33 +05:30
|
|
|
namespace FS {
|
2015-05-28 23:08:29 +05:30
|
|
|
|
2022-07-30 23:12:33 +05:30
|
|
|
class FileSystemException : public ::Exception {
|
|
|
|
public:
|
|
|
|
FileSystemException(const QString& message) : Exception(message) {}
|
2015-09-05 22:16:57 +05:30
|
|
|
};
|
|
|
|
|
2015-10-05 05:17:27 +05:30
|
|
|
/**
|
|
|
|
* write data to a file safely
|
|
|
|
*/
|
2022-07-30 23:12:33 +05:30
|
|
|
void write(const QString& filename, const QByteArray& data);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* read data from a file safely\
|
|
|
|
*/
|
2022-07-30 23:12:33 +05:30
|
|
|
QByteArray read(const QString& filename);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2016-11-17 08:39:24 +05:30
|
|
|
/**
|
|
|
|
* Update the last changed timestamp of an existing file
|
|
|
|
*/
|
2022-07-30 23:12:33 +05:30
|
|
|
bool updateTimestamp(const QString& filename);
|
2016-11-17 08:39:24 +05:30
|
|
|
|
2015-10-05 05:17:27 +05:30
|
|
|
/**
|
|
|
|
* Creates all the folders in a path for the specified path
|
|
|
|
* last segment of the path is treated as a file name and is ignored!
|
|
|
|
*/
|
2021-07-25 22:41:59 +05:30
|
|
|
bool ensureFilePathExists(QString filenamepath);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates all the folders in a path for the specified path
|
|
|
|
* last segment of the path is treated as a folder name and is created!
|
|
|
|
*/
|
2021-07-25 22:41:59 +05:30
|
|
|
bool ensureFolderPathExists(QString filenamepath);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2023-02-07 12:35:06 +05:30
|
|
|
/**
|
|
|
|
* @brief Copies a directory and it's contents from src to dest
|
|
|
|
*/
|
2022-10-23 03:06:47 +05:30
|
|
|
class copy : public QObject {
|
|
|
|
Q_OBJECT
|
2022-07-30 23:12:33 +05:30
|
|
|
public:
|
2022-10-23 03:06:47 +05:30
|
|
|
copy(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent)
|
2018-07-15 18:21:05 +05:30
|
|
|
{
|
2022-05-02 22:40:45 +05:30
|
|
|
m_src.setPath(src);
|
|
|
|
m_dst.setPath(dst);
|
2018-07-15 18:21:05 +05:30
|
|
|
}
|
2022-07-30 23:12:33 +05:30
|
|
|
copy& followSymlinks(const bool follow)
|
2018-07-15 18:21:05 +05:30
|
|
|
{
|
|
|
|
m_followSymlinks = follow;
|
|
|
|
return *this;
|
|
|
|
}
|
2022-10-23 02:55:14 +05:30
|
|
|
copy& matcher(const IPathMatcher* filter)
|
2018-07-15 18:21:05 +05:30
|
|
|
{
|
2022-10-23 02:55:14 +05:30
|
|
|
m_matcher = filter;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
copy& whitelist(bool whitelist)
|
|
|
|
{
|
|
|
|
m_whitelist = whitelist;
|
2018-07-15 18:21:05 +05:30
|
|
|
return *this;
|
|
|
|
}
|
2022-10-23 03:06:47 +05:30
|
|
|
|
|
|
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
|
|
|
|
|
|
|
int totalCopied() { return m_copied; }
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void fileCopied(const QString& relativeName);
|
|
|
|
// TODO: maybe add a "shouldCopy" signal in the future?
|
2015-10-10 09:25:55 +05:30
|
|
|
|
2022-07-30 23:12:33 +05:30
|
|
|
private:
|
2022-10-23 03:06:47 +05:30
|
|
|
bool operator()(const QString& offset, bool dryRun = false);
|
2015-10-10 09:25:55 +05:30
|
|
|
|
2022-07-30 23:12:33 +05:30
|
|
|
private:
|
2018-07-15 18:21:05 +05:30
|
|
|
bool m_followSymlinks = true;
|
2022-10-23 02:55:14 +05:30
|
|
|
const IPathMatcher* m_matcher = nullptr;
|
|
|
|
bool m_whitelist = false;
|
2018-07-15 18:21:05 +05:30
|
|
|
QDir m_src;
|
|
|
|
QDir m_dst;
|
2022-10-23 03:06:47 +05:30
|
|
|
int m_copied;
|
2015-10-10 09:25:55 +05:30
|
|
|
};
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2023-02-08 14:05:03 +05:30
|
|
|
struct LinkPair {
|
|
|
|
QString src;
|
|
|
|
QString dst;
|
|
|
|
};
|
|
|
|
|
2023-02-09 02:06:15 +05:30
|
|
|
struct LinkResult {
|
|
|
|
QString src;
|
|
|
|
QString dst;
|
|
|
|
QString err_msg;
|
|
|
|
int err_value;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ExternalLinkFileProcess : public QThread {
|
2023-02-08 14:05:03 +05:30
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2023-02-09 02:06:15 +05:30
|
|
|
ExternalLinkFileProcess(QString server, bool useHardLinks, QObject* parent = nullptr)
|
2023-02-09 07:22:50 +05:30
|
|
|
: QThread(parent), m_useHardLinks(useHardLinks), m_server(server)
|
2023-02-09 02:06:15 +05:30
|
|
|
{}
|
2023-02-08 14:05:03 +05:30
|
|
|
|
2023-02-09 02:06:15 +05:30
|
|
|
void run() override
|
|
|
|
{
|
2023-02-08 14:05:03 +05:30
|
|
|
runLinkFile();
|
|
|
|
emit processExited();
|
|
|
|
}
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void processExited();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void runLinkFile();
|
|
|
|
|
2023-02-09 02:06:15 +05:30
|
|
|
bool m_useHardLinks = false;
|
|
|
|
|
2023-02-08 14:05:03 +05:30
|
|
|
QString m_server;
|
|
|
|
};
|
|
|
|
|
2023-02-07 12:35:06 +05:30
|
|
|
/**
|
2023-02-08 14:05:03 +05:30
|
|
|
* @brief links (a file / a directory and it's contents) from src to dest
|
2023-02-07 12:35:06 +05:30
|
|
|
*/
|
|
|
|
class create_link : public QObject {
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2023-02-08 14:05:03 +05:30
|
|
|
create_link(const QList<LinkPair> path_pairs, QObject* parent = nullptr) : QObject(parent)
|
|
|
|
{
|
|
|
|
m_path_pairs.append(path_pairs);
|
|
|
|
}
|
2023-02-07 12:35:06 +05:30
|
|
|
create_link(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent)
|
|
|
|
{
|
2023-02-08 14:05:03 +05:30
|
|
|
LinkPair pair = {src, dst};
|
|
|
|
m_path_pairs.append(pair);
|
2023-02-07 12:35:06 +05:30
|
|
|
}
|
|
|
|
create_link& useHardLinks(const bool useHard)
|
|
|
|
{
|
|
|
|
m_useHardLinks = useHard;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
create_link& matcher(const IPathMatcher* filter)
|
|
|
|
{
|
|
|
|
m_matcher = filter;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
create_link& whitelist(bool whitelist)
|
|
|
|
{
|
|
|
|
m_whitelist = whitelist;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
create_link& linkRecursively(bool recursive)
|
|
|
|
{
|
|
|
|
m_recursive = recursive;
|
|
|
|
return *this;
|
|
|
|
}
|
2023-02-10 08:18:40 +05:30
|
|
|
create_link& setMaxDepth(int depth)
|
|
|
|
{
|
|
|
|
m_max_depth = depth;
|
|
|
|
return *this;
|
|
|
|
}
|
2023-02-07 12:35:06 +05:30
|
|
|
create_link& debug(bool d)
|
|
|
|
{
|
|
|
|
m_debug = d;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2023-02-08 14:05:03 +05:30
|
|
|
std::error_code getOSError() {
|
|
|
|
return m_os_err;
|
2023-02-07 12:35:06 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
|
|
|
|
2023-02-09 04:00:45 +05:30
|
|
|
int totalLinked() { return m_linked; }
|
|
|
|
|
|
|
|
|
2023-02-09 02:06:15 +05:30
|
|
|
void runPrivlaged() { runPrivlaged(QString()); }
|
|
|
|
void runPrivlaged(const QString& offset);
|
2023-02-08 14:05:03 +05:30
|
|
|
|
2023-02-09 04:00:45 +05:30
|
|
|
QList<LinkResult> getResults() { return m_path_results; }
|
|
|
|
|
2023-02-07 12:35:06 +05:30
|
|
|
|
|
|
|
signals:
|
2023-02-09 02:06:15 +05:30
|
|
|
void fileLinked(const QString& srcName, const QString& dstName);
|
|
|
|
void linkFailed(const QString& srcName, const QString& dstName, const QString& err_msg, int err_value);
|
|
|
|
void finished();
|
2023-02-09 04:00:45 +05:30
|
|
|
void finishedPrivlaged(bool gotResults);
|
|
|
|
|
2023-02-07 12:35:06 +05:30
|
|
|
|
|
|
|
private:
|
|
|
|
bool operator()(const QString& offset, bool dryRun = false);
|
2023-02-09 02:06:15 +05:30
|
|
|
void make_link_list(const QString& offset);
|
|
|
|
bool make_links();
|
2023-02-07 12:35:06 +05:30
|
|
|
|
|
|
|
private:
|
|
|
|
bool m_useHardLinks = false;
|
|
|
|
const IPathMatcher* m_matcher = nullptr;
|
|
|
|
bool m_whitelist = false;
|
|
|
|
bool m_recursive = true;
|
2023-02-08 14:05:03 +05:30
|
|
|
|
2023-02-10 08:18:40 +05:30
|
|
|
/// @brief >= -1 = infinite, 0 = link files at src/* to dest/*, 1 = link files at src/*/* to dest/*/*, etc.
|
|
|
|
int m_max_depth = -1;
|
|
|
|
|
2023-02-08 14:05:03 +05:30
|
|
|
QList<LinkPair> m_path_pairs;
|
2023-02-09 02:06:15 +05:30
|
|
|
QList<LinkResult> m_path_results;
|
|
|
|
QList<LinkPair> m_links_to_make;
|
2023-02-08 14:05:03 +05:30
|
|
|
|
2023-02-07 12:35:06 +05:30
|
|
|
int m_linked;
|
|
|
|
bool m_debug = false;
|
2023-02-08 14:05:03 +05:30
|
|
|
std::error_code m_os_err;
|
|
|
|
|
|
|
|
QLocalServer m_linkServer;
|
2023-02-07 12:35:06 +05:30
|
|
|
};
|
|
|
|
|
2022-12-30 05:51:54 +05:30
|
|
|
/**
|
|
|
|
* @brief moves a file by renaming it
|
|
|
|
* @param source source file path
|
|
|
|
* @param dest destination filepath
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool move(const QString& source, const QString& dest);
|
|
|
|
|
2015-10-05 05:17:27 +05:30
|
|
|
/**
|
|
|
|
* Delete a folder recursively
|
|
|
|
*/
|
2021-07-25 22:41:59 +05:30
|
|
|
bool deletePath(QString path);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2022-07-30 23:12:33 +05:30
|
|
|
/**
|
|
|
|
* Trash a folder / file
|
|
|
|
*/
|
2022-12-14 20:32:04 +05:30
|
|
|
bool trash(QString path, QString *pathInTrash = nullptr);
|
2022-07-30 23:12:33 +05:30
|
|
|
|
|
|
|
QString PathCombine(const QString& path1, const QString& path2);
|
|
|
|
QString PathCombine(const QString& path1, const QString& path2, const QString& path3);
|
|
|
|
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2023-02-10 08:18:40 +05:30
|
|
|
QString AbsolutePath(const QString& path);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief depth of path. "foo.txt" -> 0 , "bar/foo.txt" -> 1, /baz/bar/foo.txt -> 2, etc.
|
|
|
|
*
|
|
|
|
* @param path path to measure
|
|
|
|
* @return int number of componants before base path
|
|
|
|
*/
|
|
|
|
int PathDepth(const QString& path);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief cut off segments of path untill it is a max of length depth
|
|
|
|
*
|
|
|
|
* @param path path to truncate
|
|
|
|
* @param depth max depth of new path
|
|
|
|
* @return QString truncated path
|
|
|
|
*/
|
|
|
|
QString PathTruncate(const QString& path, int depth);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve an executable
|
|
|
|
*
|
|
|
|
* Will resolve:
|
|
|
|
* single executable (by name)
|
|
|
|
* relative path
|
|
|
|
* absolute path
|
|
|
|
*
|
|
|
|
* @return absolute path to executable or null string
|
|
|
|
*/
|
2021-07-25 22:41:59 +05:30
|
|
|
QString ResolveExecutable(QString path);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Normalize path
|
|
|
|
*
|
|
|
|
* Any paths inside the current directory will be normalized to relative paths (to current)
|
|
|
|
* Other paths will be made absolute
|
|
|
|
*
|
|
|
|
* Returns false if the path logic somehow filed (and normalizedPath in invalid)
|
|
|
|
*/
|
2021-07-25 22:41:59 +05:30
|
|
|
QString NormalizePath(QString path);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2021-07-25 22:41:59 +05:30
|
|
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-');
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2021-07-25 22:41:59 +05:30
|
|
|
QString DirNameFromString(QString string, QString inDir = ".");
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
/// Checks if the a given Path contains "!"
|
2021-07-25 22:41:59 +05:30
|
|
|
bool checkProblemticPathJava(QDir folder);
|
2015-10-05 05:17:27 +05:30
|
|
|
|
|
|
|
// Get the Directory representing the User's Desktop
|
2021-07-25 22:41:59 +05:30
|
|
|
QString getDesktopDir();
|
2015-10-05 05:17:27 +05:30
|
|
|
|
2022-06-11 22:13:09 +05:30
|
|
|
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
|
|
|
// Equivalent to doing QDir::rename, but allowing for overrides
|
|
|
|
bool overrideFolder(QString overwritten_path, QString override_path);
|
2022-10-22 20:26:27 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a shortcut to the specified target file at the specified destination path.
|
|
|
|
*/
|
|
|
|
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
|
2023-02-09 12:12:13 +05:30
|
|
|
|
|
|
|
enum class FilesystemType {
|
|
|
|
FAT,
|
|
|
|
NTFS,
|
2023-02-10 19:04:48 +05:30
|
|
|
REFS,
|
2023-02-09 12:12:13 +05:30
|
|
|
EXT,
|
|
|
|
EXT_2_OLD,
|
|
|
|
EXT_2_3_4,
|
|
|
|
XFS,
|
|
|
|
BTRFS,
|
|
|
|
NFS,
|
|
|
|
ZFS,
|
|
|
|
APFS,
|
|
|
|
HFS,
|
|
|
|
HFSPLUS,
|
|
|
|
HFSX,
|
2023-02-09 14:32:40 +05:30
|
|
|
FUSEBLK,
|
2023-02-10 04:49:38 +05:30
|
|
|
F2FS,
|
2023-02-09 12:12:13 +05:30
|
|
|
UNKNOWN
|
|
|
|
};
|
|
|
|
|
|
|
|
static const QMap<FilesystemType, QString> s_filesystem_type_names = {
|
|
|
|
{FilesystemType::FAT, QString("FAT")},
|
|
|
|
{FilesystemType::NTFS, QString("NTFS")},
|
2023-02-10 19:04:48 +05:30
|
|
|
{FilesystemType::REFS, QString("REFS")},
|
2023-02-09 12:12:13 +05:30
|
|
|
{FilesystemType::EXT, QString("EXT")},
|
|
|
|
{FilesystemType::EXT_2_OLD, QString("EXT2_OLD")},
|
|
|
|
{FilesystemType::EXT_2_3_4, QString("EXT2/3/4")},
|
|
|
|
{FilesystemType::XFS, QString("XFS")},
|
|
|
|
{FilesystemType::BTRFS, QString("BTRFS")},
|
|
|
|
{FilesystemType::NFS, QString("NFS")},
|
|
|
|
{FilesystemType::ZFS, QString("ZFS")},
|
|
|
|
{FilesystemType::APFS, QString("APFS")},
|
|
|
|
{FilesystemType::HFS, QString("HFS")},
|
|
|
|
{FilesystemType::HFSPLUS, QString("HFSPLUS")},
|
|
|
|
{FilesystemType::HFSX, QString("HFSX")},
|
2023-02-09 14:32:40 +05:30
|
|
|
{FilesystemType::FUSEBLK, QString("FUSEBLK")},
|
2023-02-10 04:49:38 +05:30
|
|
|
{FilesystemType::F2FS, QString("F2FS")},
|
2023-02-09 12:12:13 +05:30
|
|
|
{FilesystemType::UNKNOWN, QString("UNKNOWN")}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const QMap<QString, FilesystemType> s_filesystem_type_names_inverse = {
|
|
|
|
{QString("FAT"), FilesystemType::FAT},
|
|
|
|
{QString("NTFS"), FilesystemType::NTFS},
|
2023-02-10 19:04:48 +05:30
|
|
|
{QString("REFS"), FilesystemType::REFS},
|
2023-02-09 12:12:13 +05:30
|
|
|
{QString("EXT2_OLD"), FilesystemType::EXT_2_OLD},
|
|
|
|
{QString("EXT2"), FilesystemType::EXT_2_3_4},
|
|
|
|
{QString("EXT3"), FilesystemType::EXT_2_3_4},
|
|
|
|
{QString("EXT4"), FilesystemType::EXT_2_3_4},
|
|
|
|
{QString("EXT"), FilesystemType::EXT},
|
|
|
|
{QString("XFS"), FilesystemType::XFS},
|
|
|
|
{QString("BTRFS"), FilesystemType::BTRFS},
|
|
|
|
{QString("NFS"), FilesystemType::NFS},
|
|
|
|
{QString("ZFS"), FilesystemType::ZFS},
|
|
|
|
{QString("APFS"), FilesystemType::APFS},
|
|
|
|
{QString("HFSPLUS"), FilesystemType::HFSPLUS},
|
|
|
|
{QString("HFSX"), FilesystemType::HFSX},
|
|
|
|
{QString("HFS"), FilesystemType::HFS},
|
2023-02-09 14:32:40 +05:30
|
|
|
{QString("FUSEBLK"), FilesystemType::FUSEBLK},
|
2023-02-10 04:49:38 +05:30
|
|
|
{QString("F2FS"), FilesystemType::F2FS},
|
2023-02-09 12:12:13 +05:30
|
|
|
{QString("UNKNOWN"), FilesystemType::UNKNOWN}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline QString getFilesystemTypeName(FilesystemType type) {
|
|
|
|
return s_filesystem_type_names.constFind(type).value();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FilesystemInfo {
|
|
|
|
FilesystemType fsType = FilesystemType::UNKNOWN;
|
2023-02-11 06:11:48 +05:30
|
|
|
QString fsTypeName;
|
2023-02-09 12:12:13 +05:30
|
|
|
int blockSize;
|
|
|
|
qint64 bytesAvailable;
|
|
|
|
qint64 bytesFree;
|
|
|
|
qint64 bytesTotal;
|
|
|
|
QString name;
|
|
|
|
QString rootPath;
|
|
|
|
};
|
|
|
|
|
2023-02-10 19:04:48 +05:30
|
|
|
/**
|
|
|
|
* @brief path to the near ancestor that exsists
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
QString NearestExistentAncestor(const QString& path);
|
|
|
|
|
2023-02-09 12:12:13 +05:30
|
|
|
/**
|
|
|
|
* @brief colect information about the filesystem under a file
|
|
|
|
*
|
|
|
|
*/
|
2023-02-10 19:04:48 +05:30
|
|
|
FilesystemInfo statFS(const QString& path);
|
2023-02-09 12:12:13 +05:30
|
|
|
|
|
|
|
|
|
|
|
static const QList<FilesystemType> s_clone_filesystems = {
|
2023-02-10 19:04:48 +05:30
|
|
|
FilesystemType::BTRFS, FilesystemType::APFS, FilesystemType::ZFS, FilesystemType::XFS, FilesystemType::REFS
|
2023-02-09 12:12:13 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief if the Filesystem is reflink/clone capable
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool canCloneOnFS(const QString& path);
|
|
|
|
bool canCloneOnFS(const FilesystemInfo& info);
|
|
|
|
bool canCloneOnFS(FilesystemType type);
|
|
|
|
|
|
|
|
/**
|
2023-02-10 04:49:38 +05:30
|
|
|
* @brief if the Filesystems are reflink/clone capable and both are on the same device
|
2023-02-09 12:12:13 +05:30
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool canClone(const QString& src, const QString& dst);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Copies a directory and it's contents from src to dest
|
|
|
|
*/
|
|
|
|
class clone : public QObject {
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
clone(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent)
|
|
|
|
{
|
|
|
|
m_src.setPath(src);
|
|
|
|
m_dst.setPath(dst);
|
|
|
|
}
|
|
|
|
clone& matcher(const IPathMatcher* filter)
|
|
|
|
{
|
|
|
|
m_matcher = filter;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
clone& whitelist(bool whitelist)
|
|
|
|
{
|
|
|
|
m_whitelist = whitelist;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
|
|
|
|
|
|
|
int totalCloned() { return m_cloned; }
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void fileCloned(const QString& src, const QString& dst);
|
|
|
|
void cloneFailed(const QString& src, const QString& dst);
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool operator()(const QString& offset, bool dryRun = false);
|
|
|
|
|
|
|
|
private:
|
|
|
|
const IPathMatcher* m_matcher = nullptr;
|
|
|
|
bool m_whitelist = false;
|
|
|
|
QDir m_src;
|
|
|
|
QDir m_dst;
|
|
|
|
int m_cloned;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief clone/reflink file from src to dst
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool clone_file(const QString& src, const QString& dst, std::error_code& ec);
|
|
|
|
|
2023-02-10 19:04:48 +05:30
|
|
|
#if defined(Q_OS_WIN)
|
2023-02-11 06:11:48 +05:30
|
|
|
|
2023-02-10 19:04:48 +05:30
|
|
|
bool winbtrfs_clone(const std::wstring& src_path, const std::wstring& dst_path, std::error_code& ec);
|
|
|
|
bool refs_clone(const std::wstring& src_path, const std::wstring& dst_path, std::error_code& ec);
|
2023-02-11 06:11:48 +05:30
|
|
|
bool ioctl_clone(const std::wstring& src_path, const std::wstring& dst_path, std::error_code& ec);
|
|
|
|
|
|
|
|
#define USE_IOCTL_CLONE true
|
|
|
|
|
2023-02-10 19:04:48 +05:30
|
|
|
#elif defined(Q_OS_LINUX)
|
|
|
|
bool linux_ficlone(const std::string& src_path, const std::string& dst_path, std::error_code& ec);
|
|
|
|
#elif defined(Q_OS_MACOS) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
|
|
bool macos_bsd_clonefile(const std::string& src_path, const std::string& dst_path, std::error_code& ec);
|
|
|
|
#endif
|
2023-02-10 04:49:38 +05:30
|
|
|
|
|
|
|
static const QList<FilesystemType> s_non_link_filesystems = {
|
|
|
|
FilesystemType::FAT,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief if the Filesystem is symlink capable
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool canLinkOnFS(const QString& path);
|
|
|
|
bool canLinkOnFS(const FilesystemInfo& info);
|
|
|
|
bool canLinkOnFS(FilesystemType type);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief if the Filesystem is symlink capable on both ends
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
bool canLink(const QString& src, const QString& dst);
|
|
|
|
|
2023-02-12 15:14:39 +05:30
|
|
|
uintmax_t hardLinkCount(const QString& path);
|
|
|
|
|
2015-05-28 23:08:29 +05:30
|
|
|
}
|