Add basic support for UDF filesystem

For reading UDF label and UUID is needed blkid >= 2.30. For creating new
UDF filesystem is needed mkudffs binary from the udftools package.

When creating new UDF fileystem, revision 2.01 for hard disk media is used.
Therefore it is not possible to use it for optical (or other) medias.

Problems:
* Check for min and max capacity is incorrect as it depends on logical
  (sector) size of the disk.
* Check for max label length is incorrect too as it depends on characters
  itself in label.
* Specifying label is not working yet as FileSystem::create() does not get
  label parameter.
* UDF filesystem should be used on unpartitioned disk, without MBR or GPT
  and spanning whole disk, but KDE Partition Manager does not support it.
* When MBR is used, MBR partition id should be 0x07, but currently it is
  incorrect 0x83. See: https://serverfault.com/a/829172 (same for GPT)
This commit is contained in:
Pali Rohár 2017-08-17 11:07:24 +03:00 committed by Andrius Štikonas
parent da94c66601
commit feec00f4e7
8 changed files with 208 additions and 2 deletions

View File

@ -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/)

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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;

121
src/fs/udf.cpp Normal file
View File

@ -0,0 +1,121 @@
/*************************************************************************
* Copyright (C) 2017 by Pali Rohár <pali.rohar@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "fs/udf.h"
#include "util/externalcommand.h"
#include "util/capacity.h"
#include "util/report.h"
#include <KLocalizedString>
#include <QString>
#include <QStringList>
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <unistd.h>
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;
}
}

77
src/fs/udf.h Normal file
View File

@ -0,0 +1,77 @@
/*************************************************************************
* Copyright (C) 2017 by Pali Rohár <pali.rohar@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(UDF__H)
#define UDF__H
#include "util/libpartitionmanagerexport.h"
#include "fs/filesystem.h"
#include <QtGlobal>
class Report;
class QString;
namespace FS
{
/** A udf file system.
@author Pali Rohár <pali.rohar@gmail.com>
*/
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

View File

@ -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;
}