diff --git a/CMakeLists.txt b/CMakeLists.txt index 85a91f5..5508329 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ kde_enable_exceptions() find_package(PkgConfig REQUIRED) -pkg_check_modules(BLKID REQUIRED blkid>=2.23) +pkg_check_modules(BLKID REQUIRED blkid>=2.30) pkg_check_modules(LIBATASMART REQUIRED libatasmart) include_directories(${Qt5Core_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${BLKID_INCLUDE_DIRS} lib/ src/) diff --git a/src/fs/CMakeLists.txt b/src/fs/CMakeLists.txt index 47a5bee..441231a 100644 --- a/src/fs/CMakeLists.txt +++ b/src/fs/CMakeLists.txt @@ -22,6 +22,7 @@ set(FS_SRC fs/ocfs2.cpp fs/reiser4.cpp fs/reiserfs.cpp + fs/udf.cpp fs/ufs.cpp fs/unformatted.cpp fs/unknown.cpp @@ -53,6 +54,7 @@ set(FS_LIB_HDRS fs/ocfs2.h fs/reiser4.h fs/reiserfs.h + fs/udf.h fs/ufs.h fs/unformatted.h fs/unknown.h diff --git a/src/fs/filesystem.cpp b/src/fs/filesystem.cpp index a07ef89..801eb66 100644 --- a/src/fs/filesystem.cpp +++ b/src/fs/filesystem.cpp @@ -408,6 +408,7 @@ static const QString* typeNames() xi18nc("@item filesystem name", "nilfs2"), xi18nc("@item filesystem name", "lvm2 pv"), xi18nc("@item filesystem name", "f2fs"), + xi18nc("@item filesystem name", "udf"), }; return s; diff --git a/src/fs/filesystem.h b/src/fs/filesystem.h index 8e01f58..8411f83 100644 --- a/src/fs/filesystem.h +++ b/src/fs/filesystem.h @@ -84,8 +84,9 @@ public: Nilfs2 = 23, Lvm2_PV = 24, F2fs = 25, + Udf = 26, - __lastType = 26 + __lastType = 27 }; /** The type of support for a given FileSystem action */ diff --git a/src/fs/filesystemfactory.cpp b/src/fs/filesystemfactory.cpp index ebc70d2..e357657 100644 --- a/src/fs/filesystemfactory.cpp +++ b/src/fs/filesystemfactory.cpp @@ -40,6 +40,7 @@ #include "fs/ocfs2.h" #include "fs/reiser4.h" #include "fs/reiserfs.h" +#include "fs/udf.h" #include "fs/ufs.h" #include "fs/unformatted.h" #include "fs/unknown.h" @@ -78,6 +79,7 @@ void FileSystemFactory::init() m_FileSystems.insert(FileSystem::Ocfs2, new FS::ocfs2(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::ReiserFS, new FS::reiserfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Reiser4, new FS::reiser4(-1, -1, -1, QString())); + m_FileSystems.insert(FileSystem::Udf, new FS::udf(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Ufs, new FS::ufs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Unformatted, new FS::unformatted(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Unknown, new FS::unknown(-1, -1, -1, QString())); @@ -124,6 +126,7 @@ FileSystem* FileSystemFactory::create(FileSystem::Type t, qint64 firstsector, qi case FileSystem::Ocfs2: fs = new FS::ocfs2(firstsector, lastsector, sectorsused, label); break; case FileSystem::ReiserFS: fs = new FS::reiserfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Reiser4: fs = new FS::reiser4(firstsector, lastsector, sectorsused, label); break; + case FileSystem::Udf: fs = new FS::udf(firstsector, lastsector, sectorsused, label); break; case FileSystem::Ufs: fs = new FS::ufs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Unformatted: fs = new FS::unformatted(firstsector, lastsector, sectorsused, label); break; case FileSystem::Unknown: fs = new FS::unknown(firstsector, lastsector, sectorsused, label); break; diff --git a/src/fs/udf.cpp b/src/fs/udf.cpp new file mode 100644 index 0000000..1861238 --- /dev/null +++ b/src/fs/udf.cpp @@ -0,0 +1,121 @@ +/************************************************************************* + * Copyright (C) 2017 by Pali Rohár * + * * + * 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; either version 3 of * + * the License, or (at your option) any later version. * + * * + * 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 .* + *************************************************************************/ + +#include "fs/udf.h" + +#include "util/externalcommand.h" +#include "util/capacity.h" +#include "util/report.h" + +#include + +#include +#include + +#include +#include +#include +#include + +namespace FS +{ +constexpr qint64 MIN_UDF_BLOCKS = 282; +constexpr qint64 MAX_UDF_BLOCKS = ((1ULL << 32) - 1); + +FileSystem::CommandSupportType udf::m_Create = FileSystem::cmdSupportNone; + +udf::udf(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label) : + FileSystem(firstsector, lastsector, sectorsused, label, FileSystem::Udf) +{ +} + +void udf::init() +{ + m_Create = findExternal(QStringLiteral("mkudffs"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone; +} + +bool udf::supportToolFound() const +{ + return m_Create != cmdSupportNone; +} + +FileSystem::SupportTool udf::supportToolName() const +{ + return SupportTool(QStringLiteral("udftools"), QUrl(QStringLiteral("https://github.com/pali/udftools"))); +} + + +qint64 udf::minCapacity() const +{ + // TODO: Capacity depends on logical (sector) size of disk, now hardcoded as 512 + return MIN_UDF_BLOCKS * 512; +} + +qint64 udf::maxCapacity() const +{ + // TODO: Capacity depends on logical (sector) size of disk, now hardcoded as 4096 + return MAX_UDF_BLOCKS * 4096; +} + +qint64 udf::maxLabelLength() const +{ + return 126; // and only 63 if label contains character above U+FF +} + +bool udf::create(Report& report, const QString& deviceNode) +{ + // mkudffs from udftools prior to 1.1 does not check for partition limits and crashes + if ( length() > MAX_UDF_BLOCKS ) { + report.line() << xi18nc("@info:status", "Partition is too large"); + return false; + } + if ( length() < MIN_UDF_BLOCKS ) { + report.line() << xi18nc("@info:status", "Partition is too small"); + return false; + } + + // mkudffs from udftools prior to 1.1 is not able to detect logical (sector) size + // and UDF block size must match logical sector size of underlying media + int fd = open(deviceNode.toLocal8Bit().data(), O_RDONLY); + if ( fd < 0 ) { + report.line() << xi18nc("@info:status", "Cannot open device node"); + return false; + } + int blksize; + int ret = ioctl(fd, BLKSSZGET, &blksize); + close(fd); + + if ( ret != 0 ) { + report.line() << xi18nc("@info:status", "Cannot read logical (sector) size of device node"); + return false; + } + + ExternalCommand cmd(report, QStringLiteral("mkudffs"), { + QStringLiteral("--utf8"), + // TODO: Add GUI option for choosing different optical disks and UDF revision + // For now format as UDF revision 2.01 for hard disk media type + QStringLiteral("--media-type=hd"), + QStringLiteral("--udfrev=0x201"), + QStringLiteral("--blocksize=") + QString::number(blksize), + // TODO: Pass label as udf::create() parameter + // QStringLiteral("--lvid=") + label, + // QStringLiteral("--vid=") + shortlabel, + deviceNode + }); + return cmd.run(-1) && cmd.exitCode() == 0; +} +} diff --git a/src/fs/udf.h b/src/fs/udf.h new file mode 100644 index 0000000..eeae9c1 --- /dev/null +++ b/src/fs/udf.h @@ -0,0 +1,77 @@ +/************************************************************************* + * Copyright (C) 2017 by Pali Rohár * + * * + * 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; either version 3 of * + * the License, or (at your option) any later version. * + * * + * 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 .* + *************************************************************************/ + +#if !defined(UDF__H) + +#define UDF__H + +#include "util/libpartitionmanagerexport.h" + +#include "fs/filesystem.h" + +#include + +class Report; + +class QString; + +namespace FS +{ +/** A udf file system. + @author Pali Rohár + */ +class LIBKPMCORE_EXPORT udf : public FileSystem +{ +public: + udf(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label); + +public: + void init() override; + + bool create(Report& report, const QString& deviceNode) override; + + CommandSupportType supportGetLabel() const override { + return cmdSupportCore; + } + CommandSupportType supportCreate() const override { + return m_Create; + } + CommandSupportType supportMove() const override { + return cmdSupportCore; + } + CommandSupportType supportCopy() const override { + return cmdSupportCore; + } + CommandSupportType supportBackup() const override { + return cmdSupportCore; + } + CommandSupportType supportGetUUID() const override { + return cmdSupportCore; + } + + qint64 minCapacity() const override; + qint64 maxCapacity() const override; + qint64 maxLabelLength() const override; + SupportTool supportToolName() const override; + bool supportToolFound() const override; + +public: + static CommandSupportType m_Create; +}; +} + +#endif diff --git a/src/plugins/libparted/libpartedbackend.cpp b/src/plugins/libparted/libpartedbackend.cpp index 8f4b5cd..86c9a77 100644 --- a/src/plugins/libparted/libpartedbackend.cpp +++ b/src/plugins/libparted/libpartedbackend.cpp @@ -512,6 +512,7 @@ FileSystem::Type LibPartedBackend::detectFileSystem(const QString& partitionPath else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Nilfs2; else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Lvm2_PV; else if (s == QStringLiteral("f2fs")) rval = FileSystem::F2fs; + else if (s == QStringLiteral("udf")) rval = FileSystem::Udf; else qWarning() << "blkid: unknown file system type " << s << " on " << partitionPath; }