File indexing completed on 2024-05-19 03:56:20

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 2011 David Faure <faure@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only
0007 */
0008 
0009 #include "kfilesystemtype.h"
0010 #include "knetworkmounts.h"
0011 
0012 #include <config-kfilesystemtype.h>
0013 #if HAVE_UDEV
0014 #include <libudev.h>
0015 #endif
0016 
0017 #include <QCoreApplication>
0018 #include <QFile>
0019 
0020 #include <array>
0021 
0022 struct FsInfo {
0023     KFileSystemType::Type type = KFileSystemType::Unknown;
0024     const char *name = nullptr;
0025 };
0026 
0027 static const std::array<FsInfo, 19> s_fsMap = {{
0028     {KFileSystemType::Nfs, "nfs"},
0029     {KFileSystemType::Smb, "smb"},
0030     {KFileSystemType::Fat, "fat"},
0031     {KFileSystemType::Ramfs, "ramfs"},
0032     {KFileSystemType::Other, "other"},
0033     {KFileSystemType::Ntfs, "ntfs"},
0034     {KFileSystemType::Ntfs, "ntfs3"},
0035     {KFileSystemType::Exfat, "exfat"},
0036     {KFileSystemType::Unknown, "unknown"},
0037     {KFileSystemType::Nfs, "autofs"},
0038     {KFileSystemType::Nfs, "cachefs"},
0039     {KFileSystemType::Nfs, "fuse.sshfs"},
0040     {KFileSystemType::Nfs, "xtreemfs@"}, // #178678
0041     {KFileSystemType::Smb, "smbfs"},
0042     {KFileSystemType::Smb, "cifs"},
0043     {KFileSystemType::Fat, "vfat"},
0044     {KFileSystemType::Fat, "msdos"},
0045     {KFileSystemType::Fuse, "fuseblk"},
0046 }};
0047 
0048 #ifndef Q_OS_WIN
0049 inline KFileSystemType::Type kde_typeFromName(const QLatin1String name)
0050 {
0051     auto it = std::find_if(s_fsMap.cbegin(), s_fsMap.cend(), [name](const auto &fsInfo) {
0052         return QLatin1String(fsInfo.name) == name;
0053     });
0054     return it != s_fsMap.cend() ? it->type : KFileSystemType::Other;
0055 }
0056 
0057 inline KFileSystemType::Type kde_typeFromName(const char *c)
0058 {
0059     return kde_typeFromName(QLatin1String(c));
0060 }
0061 
0062 #if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)
0063 #include <sys/mount.h>
0064 #include <sys/param.h>
0065 
0066 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
0067 {
0068     struct statfs buf;
0069     if (statfs(path.constData(), &buf) != 0) {
0070         return KFileSystemType::Unknown;
0071     }
0072     return kde_typeFromName(buf.f_fstypename);
0073 }
0074 
0075 #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
0076 #include <sys/statfs.h>
0077 
0078 #ifdef Q_OS_LINUX
0079 #include <linux/magic.h> // A lot of the filesystem superblock MAGIC numbers
0080 #include <sys/stat.h>
0081 #endif
0082 
0083 // Add known missig magics
0084 // Can use https://github.com/systemd/systemd/blob/main/src/basic/missing_magic.h
0085 // as reference
0086 
0087 // From linux/fs/ntfs/ntfs.h
0088 #ifndef NTFS_SB_MAGIC
0089 #define NTFS_SB_MAGIC 0x5346544e
0090 #endif
0091 
0092 // From linux/fs/ntfs3/super.c
0093 #ifndef NTFS3_MAGIC
0094 #define NTFS3_MAGIC 0x7366746E
0095 #endif
0096 
0097 // From linux/fs/exfat/exfat_fs.h
0098 #ifndef EXFAT_SUPER_MAGIC
0099 #define EXFAT_SUPER_MAGIC 0x2011BAB0UL
0100 #endif
0101 
0102 // From linux/fs/cifs/smb2glob.h
0103 #ifndef SMB2_MAGIC_NUMBER
0104 #define SMB2_MAGIC_NUMBER 0xFE534D42
0105 #endif
0106 
0107 // From linux/fs/cifs/cifsglob.h
0108 #ifndef CIFS_MAGIC_NUMBER
0109 #define CIFS_MAGIC_NUMBER 0xFF534D42
0110 #endif
0111 
0112 // From linux/fs/fuse/inode.c
0113 #ifndef FUSE_SUPER_MAGIC
0114 #define FUSE_SUPER_MAGIC 0x65735546
0115 #endif
0116 
0117 #ifndef AUTOFSNG_SUPER_MAGIC
0118 #define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
0119 #endif
0120 
0121 #ifdef Q_OS_HURD
0122 #ifndef NFS_SUPER_MAGIC
0123 #define NFS_SUPER_MAGIC 0x00006969
0124 #endif
0125 #ifndef AUTOFS_SUPER_MAGIC
0126 #define AUTOFS_SUPER_MAGIC 0x00000187
0127 #endif
0128 #ifndef MSDOS_SUPER_MAGIC
0129 #define MSDOS_SUPER_MAGIC 0x00004d44
0130 #endif
0131 #ifndef SMB_SUPER_MAGIC
0132 #define SMB_SUPER_MAGIC 0x0000517B
0133 #endif
0134 #ifndef RAMFS_MAGIC
0135 #define RAMFS_MAGIC 0x858458F6
0136 #endif
0137 #endif
0138 
0139 KFileSystemType::Type probeFuseBlkType(const QByteArray &path)
0140 {
0141     using namespace KFileSystemType;
0142 
0143 #if HAVE_UDEV
0144     struct stat buf;
0145     if (stat(path.constData(), &buf) != 0) {
0146         return Fuse;
0147     }
0148 
0149     using UdevPtr = std::unique_ptr<struct udev, decltype(&udev_unref)>;
0150     using UDevicePtr = std::unique_ptr<struct udev_device, decltype(&udev_device_unref)>;
0151 
0152     // Code originally copied from util-linux/misc-utils/lsblk.c
0153     auto udevP = UdevPtr(udev_new(), udev_unref);
0154     if (!udevP) {
0155         return Fuse;
0156     }
0157 
0158     // 'b' for block devices
0159     auto devPtr = UDevicePtr(udev_device_new_from_devnum(udevP.get(), 'b', buf.st_dev), udev_device_unref);
0160     if (!devPtr) {
0161         // If is not block device, assume conservatively it is a remote FS under FUSE.
0162         return Nfs;
0163     }
0164 
0165     const QLatin1String fsType(udev_device_get_property_value(devPtr.get(), "ID_FS_TYPE"));
0166     return kde_typeFromName(fsType);
0167 #endif
0168 
0169     return Fuse;
0170 }
0171 
0172 // Reverse-engineering without C++ code:
0173 // strace stat -f /mnt 2>&1|grep statfs|grep mnt, and look for f_type
0174 //
0175 // Also grep'ing in /usr/src/<kernel-version>/fs/
0176 
0177 static KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
0178 {
0179     struct statfs buf;
0180     if (statfs(path.constData(), &buf) != 0) {
0181         return KFileSystemType::Unknown;
0182     }
0183 
0184     switch (static_cast<unsigned long>(buf.f_type)) {
0185     case NFS_SUPER_MAGIC:
0186     case AUTOFS_SUPER_MAGIC:
0187     case AUTOFSNG_SUPER_MAGIC:
0188         return KFileSystemType::Nfs;
0189     case FUSE_SUPER_MAGIC:
0190         return probeFuseBlkType(path);
0191     case SMB_SUPER_MAGIC:
0192     case SMB2_MAGIC_NUMBER:
0193     case CIFS_MAGIC_NUMBER:
0194         return KFileSystemType::Smb;
0195     case MSDOS_SUPER_MAGIC:
0196         return KFileSystemType::Fat;
0197     case NTFS_SB_MAGIC:
0198     case NTFS3_MAGIC:
0199         return KFileSystemType::Ntfs;
0200     case EXFAT_SUPER_MAGIC:
0201         return KFileSystemType::Exfat;
0202     case RAMFS_MAGIC:
0203         return KFileSystemType::Ramfs;
0204     default:
0205         return KFileSystemType::Other;
0206     }
0207 }
0208 
0209 #elif defined(Q_OS_AIX) || defined(Q_OS_HPUX) || defined(Q_OS_QNX) || defined(Q_OS_SCO) || defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT)                     \
0210     || defined(Q_OS_NETBSD)
0211 #include <sys/statvfs.h>
0212 
0213 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
0214 {
0215     struct statvfs buf;
0216     if (statvfs(path.constData(), &buf) != 0) {
0217         return KFileSystemType::Unknown;
0218     }
0219 #if defined(Q_OS_NETBSD)
0220     return kde_typeFromName(buf.f_fstypename);
0221 #else
0222     return kde_typeFromName(buf.f_basetype);
0223 #endif
0224 }
0225 #endif
0226 #else
0227 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
0228 {
0229     return KFileSystemType::Unknown;
0230 }
0231 #endif
0232 
0233 KFileSystemType::Type KFileSystemType::fileSystemType(const QString &path)
0234 {
0235     if (KNetworkMounts::self()->isSlowPath(path, KNetworkMounts::KNetworkMountsType::SmbPaths)) {
0236         return KFileSystemType::Smb;
0237     } else if (KNetworkMounts::self()->isSlowPath(path, KNetworkMounts::KNetworkMountsType::NfsPaths)) {
0238         return KFileSystemType::Nfs;
0239     } else {
0240         return determineFileSystemTypeImpl(QFile::encodeName(path));
0241     }
0242 }
0243 
0244 QString KFileSystemType::fileSystemName(KFileSystemType::Type type)
0245 {
0246     switch (type) {
0247     case KFileSystemType::Nfs:
0248         return QCoreApplication::translate("KFileSystemType", "NFS");
0249     case KFileSystemType::Smb:
0250         return QCoreApplication::translate("KFileSystemType", "SMB");
0251     case KFileSystemType::Fat:
0252         return QCoreApplication::translate("KFileSystemType", "FAT");
0253     case KFileSystemType::Ramfs:
0254         return QCoreApplication::translate("KFileSystemType", "RAMFS");
0255     case KFileSystemType::Other:
0256         return QCoreApplication::translate("KFileSystemType", "Other");
0257     case KFileSystemType::Ntfs:
0258         return QCoreApplication::translate("KFileSystemType", "NTFS");
0259     case KFileSystemType::Exfat:
0260         return QCoreApplication::translate("KFileSystemType", "ExFAT");
0261     case KFileSystemType::Fuse:
0262         return QCoreApplication::translate("KFileSystemType", "FUSE");
0263     case KFileSystemType::Unknown:
0264         return QCoreApplication::translate("KFileSystemType", "Unknown");
0265     }
0266 
0267     Q_UNREACHABLE();
0268     return {};
0269 }