1 /*
2     This file is part of the KDE libraries
3 
4     SPDX-FileCopyrightText: 2011 David Faure <faure@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only
7 */
8 
9 #include "kfilesystemtype.h"
10 #include "kcoreaddons_debug.h"
11 #include "knetworkmounts.h"
12 
13 #include <QCoreApplication>
14 #include <QFile>
15 
16 #ifndef Q_OS_WIN
kde_typeFromName(const char * name)17 inline KFileSystemType::Type kde_typeFromName(const char *name)
18 {
19     /* clang-format off */
20     if (qstrncmp(name, "nfs", 3) == 0
21         || qstrncmp(name, "autofs", 6) == 0
22         || qstrncmp(name, "cachefs", 7) == 0
23         || qstrncmp(name, "fuse.sshfs", 10) == 0
24         || qstrncmp(name, "xtreemfs@", 9) == 0) { // #178678
25 
26         return KFileSystemType::Nfs;
27     }
28     if (qstrncmp(name, "fat", 3) == 0
29         || qstrncmp(name, "vfat", 4) == 0
30         || qstrncmp(name, "msdos", 5) == 0) {
31         return KFileSystemType::Fat;
32     }
33     if (qstrncmp(name, "cifs", 4) == 0
34         || qstrncmp(name, "smbfs", 5) == 0) {
35         return KFileSystemType::Smb;
36     }
37     if (qstrncmp(name, "ramfs", 5) == 0) {
38         return KFileSystemType::Ramfs;
39     }
40     /* clang-format on */
41 
42     return KFileSystemType::Other;
43 }
44 
45 #if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)
46 #include <sys/mount.h>
47 #include <sys/param.h>
48 
determineFileSystemTypeImpl(const QByteArray & path)49 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
50 {
51     struct statfs buf;
52     if (statfs(path.constData(), &buf) != 0) {
53         return KFileSystemType::Unknown;
54     }
55     return kde_typeFromName(buf.f_fstypename);
56 }
57 
58 #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
59 #include <sys/statfs.h>
60 
61 #ifdef Q_OS_LINUX
62 #include <linux/magic.h> // A lot of the filesystem superblock MAGIC numbers
63 #endif
64 
65 // From /usr/src/linux-5.13.2-1-vanilla/fs/ntfs/ntfs.h
66 #ifndef NTFS_SB_MAGIC
67 #define NTFS_SB_MAGIC 0x5346544e
68 #endif
69 
70 // From /usr/src/linux-5.13.2-1-vanilla/fs/exfat/exfat_fs.h
71 #ifndef EXFAT_SUPER_MAGIC
72 #define EXFAT_SUPER_MAGIC 0x2011BAB0UL
73 #endif
74 
75 // From /usr/src/linux-5.13.2-1-vanilla/fs/cifs/smb2glob.h
76 #ifndef SMB2_MAGIC_NUMBER
77 #define SMB2_MAGIC_NUMBER 0xFE534D42
78 #endif
79 
80 // From /usr/src/linux-5.13.2-1-vanilla/fs/cifs/cifsglob.h
81 #ifndef CIFS_MAGIC_NUMBER
82 #define CIFS_MAGIC_NUMBER 0xFF534D42
83 #endif
84 
85 // From /usr/src/linux-5.13.2-1-vanilla/fs/fuse/inode.c
86 #ifndef FUSE_SUPER_MAGIC
87 #define FUSE_SUPER_MAGIC 0x65735546
88 #endif
89 
90 #ifndef AUTOFSNG_SUPER_MAGIC
91 #define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
92 #endif
93 
94 #ifdef Q_OS_HURD
95 #ifndef NFS_SUPER_MAGIC
96 #define NFS_SUPER_MAGIC 0x00006969
97 #endif
98 #ifndef AUTOFS_SUPER_MAGIC
99 #define AUTOFS_SUPER_MAGIC 0x00000187
100 #endif
101 #ifndef MSDOS_SUPER_MAGIC
102 #define MSDOS_SUPER_MAGIC 0x00004d44
103 #endif
104 #ifndef SMB_SUPER_MAGIC
105 #define SMB_SUPER_MAGIC 0x0000517B
106 #endif
107 #ifndef RAMFS_MAGIC
108 #define RAMFS_MAGIC 0x858458F6
109 #endif
110 #endif
111 
112 // Reverse-engineering without C++ code:
113 // strace stat -f /mnt 2>&1|grep statfs|grep mnt, and look for f_type
114 //
115 // Also grep'ing in /usr/src/<kernel-version>/fs/
116 
determineFileSystemTypeImpl(const QByteArray & path)117 static KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
118 {
119     struct statfs buf;
120     if (statfs(path.constData(), &buf) != 0) {
121         return KFileSystemType::Unknown;
122     }
123 
124     switch (static_cast<unsigned long>(buf.f_type)) {
125     case NFS_SUPER_MAGIC:
126     case AUTOFS_SUPER_MAGIC:
127     case AUTOFSNG_SUPER_MAGIC:
128     case FUSE_SUPER_MAGIC: // TODO could be anything. Need to use statfs() to find out more.
129         return KFileSystemType::Nfs;
130     case SMB_SUPER_MAGIC:
131     case SMB2_MAGIC_NUMBER:
132     case CIFS_MAGIC_NUMBER:
133         return KFileSystemType::Smb;
134     case MSDOS_SUPER_MAGIC:
135         return KFileSystemType::Fat;
136     case NTFS_SB_MAGIC:
137         return KFileSystemType::Ntfs;
138     case EXFAT_SUPER_MAGIC:
139         return KFileSystemType::Exfat;
140     case RAMFS_MAGIC:
141         return KFileSystemType::Ramfs;
142     default:
143         return KFileSystemType::Other;
144     }
145 }
146 
147 #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)                     \
148     || defined(Q_OS_NETBSD)
149 #include <sys/statvfs.h>
150 
determineFileSystemTypeImpl(const QByteArray & path)151 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
152 {
153     struct statvfs buf;
154     if (statvfs(path.constData(), &buf) != 0) {
155         return KFileSystemType::Unknown;
156     }
157 #if defined(Q_OS_NETBSD)
158     return kde_typeFromName(buf.f_fstypename);
159 #else
160     return kde_typeFromName(buf.f_basetype);
161 #endif
162 }
163 #endif
164 #else
determineFileSystemTypeImpl(const QByteArray & path)165 KFileSystemType::Type determineFileSystemTypeImpl(const QByteArray &path)
166 {
167     return KFileSystemType::Unknown;
168 }
169 #endif
170 
fileSystemType(const QString & path)171 KFileSystemType::Type KFileSystemType::fileSystemType(const QString &path)
172 {
173     if (KNetworkMounts::self()->isSlowPath(path, KNetworkMounts::KNetworkMountsType::SmbPaths)) {
174         return KFileSystemType::Smb;
175     } else if (KNetworkMounts::self()->isSlowPath(path, KNetworkMounts::KNetworkMountsType::NfsPaths)) {
176         return KFileSystemType::Nfs;
177     } else {
178         return determineFileSystemTypeImpl(QFile::encodeName(path));
179     }
180 }
181 
fileSystemName(KFileSystemType::Type type)182 QString KFileSystemType::fileSystemName(KFileSystemType::Type type)
183 {
184     switch (type) {
185     case KFileSystemType::Nfs:
186         return QCoreApplication::translate("KFileSystemType", "NFS");
187     case KFileSystemType::Smb:
188         return QCoreApplication::translate("KFileSystemType", "SMB");
189     case KFileSystemType::Fat:
190         return QCoreApplication::translate("KFileSystemType", "FAT");
191     case KFileSystemType::Ramfs:
192         return QCoreApplication::translate("KFileSystemType", "RAMFS");
193     case KFileSystemType::Other:
194         return QCoreApplication::translate("KFileSystemType", "Other");
195     case KFileSystemType::Ntfs:
196         return QCoreApplication::translate("KFileSystemType", "NTFS");
197     case KFileSystemType::Exfat:
198         return QCoreApplication::translate("KFileSystemType", "ExFAT");
199     case KFileSystemType::Unknown:
200         return QCoreApplication::translate("KFileSystemType", "Unknown");
201     }
202 
203     Q_UNREACHABLE();
204     return {};
205 }
206