• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kmountpoint.cpp

Go to the documentation of this file.
00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
00004  *                2007 David Faure <faure@kde.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License version 2 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kmountpoint.h"
00022 
00023 #include <config.h>
00024 #include <stdlib.h>
00025 
00026 #include <QtCore/QFile>
00027 #include <QtCore/QTextIStream>
00028 
00029 #include "kstandarddirs.h"
00030 
00031 #ifdef Q_WS_WIN
00032 #include <windows.h>
00033 #include <QDir>
00034 #endif
00035 
00036 #ifdef HAVE_VOLMGT
00037 #include <volmgt.h>
00038 #endif
00039 #ifdef HAVE_SYS_MNTTAB_H
00040 #include <sys/mnttab.h>
00041 #endif
00042 #ifdef HAVE_MNTENT_H
00043 #include <mntent.h>
00044 #elif defined(HAVE_SYS_MNTENT_H)
00045 #include <sys/mntent.h>
00046 #endif
00047 
00048 // This is the *BSD branch
00049 #ifdef HAVE_SYS_MOUNT_H
00050 #ifdef HAVE_SYS_TYPES_H
00051 #include <sys/types.h>
00052 #endif
00053 #ifdef HAVE_SYS_PARAM_H
00054 #include <sys/param.h>
00055 #endif
00056 #include <sys/mount.h>
00057 #endif
00058 
00059 #ifdef HAVE_FSTAB_H
00060 #include <fstab.h>
00061 #endif
00062 #if defined(_AIX)
00063 #include <sys/mntctl.h>
00064 #include <sys/vmount.h>
00065 #include <sys/vfs.h>
00066 /* AIX does not prototype mntctl anywhere that I can find */
00067 #ifndef mntctl
00068 extern "C" int mntctl(int command, int size, void* buffer);
00069 #endif
00070 extern "C" struct vfs_ent *getvfsbytype(int vfsType);
00071 extern "C" void endvfsent( );
00072 #endif
00073 
00074 
00075 #ifndef HAVE_GETMNTINFO
00076 # ifdef _PATH_MOUNTED
00077 // On some Linux, MNTTAB points to /etc/fstab !
00078 #  undef MNTTAB
00079 #  define MNTTAB _PATH_MOUNTED
00080 # else
00081 #  ifndef MNTTAB
00082 #   ifdef MTAB_FILE
00083 #    define MNTTAB MTAB_FILE
00084 #   else
00085 #    define MNTTAB "/etc/mnttab"
00086 #   endif
00087 #  endif
00088 # endif
00089 #endif
00090 
00091 #include "kdebug.h"
00092 
00093 
00094 #ifdef _OS_SOLARIS_
00095 #define FSTAB "/etc/vfstab"
00096 #else
00097 #define FSTAB "/etc/fstab"
00098 #endif
00099 
00100 class KMountPoint::Private {
00101 public:
00102     void finalizePossibleMountPoint(DetailsNeededFlags infoNeeded);
00103     void finalizeCurrentMountPoint(DetailsNeededFlags infoNeeded);
00104 
00105     QString mountedFrom;
00106     QString device; // Only available when the NeedRealDeviceName flag was set.
00107     QString mountPoint;
00108     QString mountType;
00109     QStringList mountOptions;
00110 };
00111 
00112 KMountPoint::KMountPoint()
00113     :d( new Private )
00114 {
00115 }
00116 
00117 KMountPoint::~KMountPoint()
00118 {
00119     delete d;
00120 }
00121 
00122 // There are (at least) four kind of APIs:
00123 // setmntent + getmntent + struct mntent (linux...)
00124 //             getmntent + struct mnttab
00125 // mntctl                + struct vmount (AIX)
00126 // getmntinfo + struct statfs&flags (BSD 4.4 and friends)
00127 // getfsent + char* (BSD 4.3 and friends)
00128 
00129 #ifdef HAVE_SETMNTENT
00130 #define SETMNTENT setmntent
00131 #define ENDMNTENT endmntent
00132 #define STRUCT_MNTENT struct mntent *
00133 #define STRUCT_SETMNTENT FILE *
00134 #define GETMNTENT(file, var) ((var = getmntent(file)) != 0)
00135 #define MOUNTPOINT(var) var->mnt_dir
00136 #define MOUNTTYPE(var) var->mnt_type
00137 #define MOUNTOPTIONS(var) var->mnt_opts
00138 #define FSNAME(var) var->mnt_fsname
00139 #else
00140 #define SETMNTENT fopen
00141 #define ENDMNTENT fclose
00142 #define STRUCT_MNTENT struct mnttab
00143 #define STRUCT_SETMNTENT FILE *
00144 #define GETMNTENT(file, var) (getmntent(file, &var) == 0)
00145 #define MOUNTPOINT(var) var.mnt_mountp
00146 #define MOUNTTYPE(var) var.mnt_fstype
00147 #define MOUNTOPTIONS(var) var.mnt_mntopts
00148 #define FSNAME(var) var.mnt_special
00149 #endif
00150 
00155 static QString devNameFromOptions(const QStringList &options)
00156 {
00157     // Search options to find the device name
00158     for ( QStringList::ConstIterator it = options.begin(); it != options.end(); ++it)
00159     {
00160         if( (*it).startsWith(QLatin1String("dev=")))
00161             return (*it).mid(4);
00162     }
00163     return QString::fromLatin1("none");
00164 }
00165 
00166 void KMountPoint::Private::finalizePossibleMountPoint(DetailsNeededFlags infoNeeded)
00167 {
00168     if (mountType == QLatin1String("supermount")) {
00169         mountedFrom = devNameFromOptions(mountOptions);
00170     }
00171 
00172     if (mountedFrom.startsWith(QLatin1String("UUID="))) {
00173         const QString uuid = mountedFrom.mid(5);
00174         const QString potentialDevice = QFile::symLinkTarget(QString::fromLatin1("/dev/disk/by-uuid/") + uuid);
00175         if (QFile::exists(potentialDevice)) {
00176             mountedFrom = potentialDevice;
00177         }
00178     }
00179     if (mountedFrom.startsWith(QLatin1String("LABEL="))) {
00180         const QString label = mountedFrom.mid(6);
00181         const QString potentialDevice = QFile::symLinkTarget(QString::fromLatin1("/dev/disk/by-label/") + label);
00182         if (QFile::exists(potentialDevice)) {
00183             mountedFrom = potentialDevice;
00184         }
00185     }
00186 
00187     if (infoNeeded & NeedRealDeviceName) {
00188         if (mountedFrom.startsWith(QLatin1Char('/')))
00189             device = KStandardDirs::realFilePath(mountedFrom);
00190     }
00191     // TODO: Strip trailing '/' ?
00192 }
00193 
00194 void KMountPoint::Private::finalizeCurrentMountPoint(DetailsNeededFlags infoNeeded)
00195 {
00196     if (infoNeeded & NeedRealDeviceName) {
00197         if (mountedFrom.startsWith(QLatin1Char('/')))
00198             device = KStandardDirs::realFilePath(mountedFrom);
00199     }
00200 }
00201 
00202 KMountPoint::List KMountPoint::possibleMountPoints(DetailsNeededFlags infoNeeded)
00203 {
00204 #ifdef Q_WS_WIN
00205     return KMountPoint::currentMountPoints(infoNeeded);
00206 #endif
00207 
00208     KMountPoint::List result;
00209 
00210 #ifdef HAVE_SETMNTENT
00211    STRUCT_SETMNTENT fstab;
00212    if ((fstab = SETMNTENT(FSTAB, "r")) == 0)
00213       return result;
00214 
00215    STRUCT_MNTENT fe;
00216    while (GETMNTENT(fstab, fe))
00217    {
00218       Ptr mp(new KMountPoint);
00219       mp->d->mountedFrom = QFile::decodeName(FSNAME(fe));
00220 
00221       mp->d->mountPoint = QFile::decodeName(MOUNTPOINT(fe));
00222       mp->d->mountType = QFile::decodeName(MOUNTTYPE(fe));
00223 
00224       //Devices using supermount have their device names in the mount options
00225       //instead of the device field. That's why we need to read the mount options
00226       if (infoNeeded & NeedMountOptions || (mp->d->mountType == QLatin1String("supermount")))
00227       {
00228          QString options = QFile::decodeName(MOUNTOPTIONS(fe));
00229          mp->d->mountOptions = options.split( QLatin1Char(',') );
00230       }
00231 
00232       mp->d->finalizePossibleMountPoint(infoNeeded);
00233 
00234       result.append(mp);
00235    }
00236    ENDMNTENT(fstab);
00237 #else
00238    QFile f(QLatin1String(FSTAB));
00239    if ( !f.open(QIODevice::ReadOnly) )
00240       return result;
00241 
00242    QTextStream t (&f);
00243    QString s;
00244 
00245    while (! t.atEnd())
00246    {
00247       s=t.readLine().simplified();
00248       if ( s.isEmpty() || (s[0] == QLatin1Char('#')))
00249           continue;
00250 
00251       // not empty or commented out by '#'
00252       const QStringList item = s.split(QLatin1Char(' '));
00253 
00254 #ifdef _OS_SOLARIS_
00255       if (item.count() < 5)
00256          continue;
00257 #else
00258       if (item.count() < 4)
00259          continue;
00260 #endif
00261 
00262       Ptr mp(new KMountPoint);
00263 
00264       int i = 0;
00265       mp->d->mountedFrom = item[i++];
00266 #ifdef _OS_SOLARIS_
00267       //device to fsck
00268       i++;
00269 #endif
00270       mp->d->mountPoint = item[i++];
00271       mp->d->mountType = item[i++];
00272       QString options = item[i++];
00273 
00274       if (infoNeeded & NeedMountOptions)
00275       {
00276          mp->d->mountOptions = options.split(QLatin1Char(','));
00277       }
00278 
00279       mp->d->finalizePossibleMountPoint(infoNeeded);
00280 
00281       result.append(mp);
00282    } //while
00283 
00284    f.close();
00285 #endif
00286    return result;
00287 }
00288 
00289 KMountPoint::List KMountPoint::currentMountPoints(DetailsNeededFlags infoNeeded)
00290 {
00291     KMountPoint::List result;
00292 
00293 #ifdef HAVE_GETMNTINFO
00294 
00295 #ifdef GETMNTINFO_USES_STATVFS
00296     struct statvfs *mounted;
00297 #else
00298     struct statfs *mounted;
00299 #endif
00300 
00301     int num_fs = getmntinfo(&mounted, MNT_NOWAIT);
00302 
00303     for (int i=0;i< num_fs;i++)
00304     {
00305       Ptr mp(new KMountPoint);
00306       mp->d->mountedFrom = QFile::decodeName(mounted[i].f_mntfromname);
00307       mp->d->mountPoint = QFile::decodeName(mounted[i].f_mntonname);
00308 
00309 #ifdef __osf__
00310       mp->d->mountType = QFile::decodeName(mnt_names[mounted[i].f_type]);
00311 #else
00312       mp->d->mountType = QFile::decodeName(mounted[i].f_fstypename);
00313 #endif
00314 
00315       if (infoNeeded & NeedMountOptions)
00316       {
00317          struct fstab *ft = getfsfile(mounted[i].f_mntonname);
00318          if (ft != 0) {
00319              QString options = QFile::decodeName(ft->fs_mntops);
00320              mp->d->mountOptions = options.split(QLatin1Char(','));
00321          } else {
00322              // TODO: get mount options if not mounted via fstab, see mounted[i].f_flags
00323          }
00324       }
00325 
00326       mp->d->finalizeCurrentMountPoint(infoNeeded);
00327       // TODO: Strip trailing '/' ?
00328       result.append(mp);
00329    }
00330 
00331 #elif defined(_AIX)
00332 
00333     struct vmount *mntctl_buffer;
00334     struct vmount *vm;
00335     char *mountedfrom;
00336     char *mountedto;
00337     int fsname_len, num;
00338     int buf_sz = 4096;
00339 
00340     mntctl_buffer = (struct vmount*)malloc(buf_sz);
00341     num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
00342     if (num == 0)
00343     {
00344     buf_sz = *(int*)mntctl_buffer;
00345     free(mntctl_buffer);
00346     mntctl_buffer = (struct vmount*)malloc(buf_sz);
00347     num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
00348     }
00349 
00350     if (num > 0)
00351     {
00352         /* iterate through items in the vmount structure: */
00353         vm = (struct vmount *)mntctl_buffer;
00354         for ( ; num > 0; --num )
00355         {
00356             /* get the name of the mounted file systems: */
00357             fsname_len = vmt2datasize(vm, VMT_STUB);
00358             mountedto     = (char*)malloc(fsname_len + 1);
00359         mountedto[fsname_len] = '\0';
00360             strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len);
00361 
00362             fsname_len = vmt2datasize(vm, VMT_OBJECT);
00363             mountedfrom     = (char*)malloc(fsname_len + 1);
00364         mountedfrom[fsname_len] = '\0';
00365             strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len);
00366 
00367         /* Look up the string for the file system type,
00368              * as listed in /etc/vfs.
00369              * ex.: nfs,jfs,afs,cdrfs,sfs,cachefs,nfs3,autofs
00370              */
00371             struct vfs_ent* ent = getvfsbytype(vm->vmt_gfstype);
00372 
00373             KMountPoint *mp = new KMountPoint;
00374             mp->d->mountedFrom = QFile::decodeName(mountedfrom);
00375             mp->d->mountPoint = QFile::decodeName(mountedto);
00376             mp->d->mountType = QFile::decodeName(ent->vfsent_name);
00377 
00378             free(mountedfrom);
00379             free(mountedto);
00380 
00381             if (infoNeeded & NeedMountOptions)
00382             {
00383               // TODO
00384             }
00385 
00386             mp->d->finalizeCurrentMountPoint(infoNeeded);
00387             result.append(mp);
00388 
00389             /* goto the next vmount structure: */
00390             vm = (struct vmount *)((char *)vm + vm->vmt_length);
00391         }
00392 
00393     endvfsent( );
00394     }
00395 
00396     free( mntctl_buffer );
00397 #elif defined(Q_WS_WIN) && !defined(_WIN32_WCE)
00398     //nothing fancy with infoNeeded but it gets the job done
00399     DWORD bits = GetLogicalDrives();
00400     if(!bits)
00401         return result;
00402 
00403     for(int i = 0; i < 26; i++)
00404     {
00405         if(bits & (1 << i))
00406         {
00407             Ptr mp(new KMountPoint);
00408             mp->d->mountPoint = QString(QLatin1Char('A' + i) + QLatin1String(":/"));
00409             result.append(mp);
00410         }
00411     }
00412 
00413 #elif defined(_WIN32_WCE)
00414     Ptr mp(new KMountPoint);
00415     mp->d->mountPoint = QString("/");
00416     result.append(mp);
00417 
00418 #else
00419    STRUCT_SETMNTENT mnttab;
00420    if ((mnttab = SETMNTENT(MNTTAB, "r")) == 0)
00421       return result;
00422 
00423    STRUCT_MNTENT fe;
00424    while (GETMNTENT(mnttab, fe))
00425    {
00426       Ptr mp(new KMountPoint);
00427       mp->d->mountedFrom = QFile::decodeName(FSNAME(fe));
00428 
00429       mp->d->mountPoint = QFile::decodeName(MOUNTPOINT(fe));
00430       mp->d->mountType = QFile::decodeName(MOUNTTYPE(fe));
00431 
00432       //Devices using supermount have their device names in the mount options
00433       //instead of the device field. That's why we need to read the mount options
00434       if (infoNeeded & NeedMountOptions || (mp->d->mountType == QLatin1String("supermount")))
00435       {
00436          QString options = QFile::decodeName(MOUNTOPTIONS(fe));
00437          mp->d->mountOptions = options.split( QLatin1Char(',') );
00438       }
00439       mp->d->finalizeCurrentMountPoint(infoNeeded);
00440 
00441       result.append(mp);
00442    }
00443    ENDMNTENT(mnttab);
00444 #endif
00445    return result;
00446 }
00447 
00448 QString KMountPoint::mountedFrom() const
00449 {
00450     return d->mountedFrom;
00451 }
00452 
00453 QString KMountPoint::realDeviceName() const
00454 {
00455     return d->device;
00456 }
00457 
00458 QString KMountPoint::mountPoint() const
00459 {
00460     return d->mountPoint;
00461 }
00462 
00463 QString KMountPoint::mountType() const
00464 {
00465     return d->mountType;
00466 }
00467 
00468 QStringList KMountPoint::mountOptions() const
00469 {
00470     return d->mountOptions;
00471 }
00472 
00473 KMountPoint::List::List()
00474     : QList<Ptr>()
00475 {
00476 }
00477 
00478 KMountPoint::Ptr KMountPoint::List::findByPath(const QString& path) const
00479 {
00480 #ifndef Q_WS_WIN
00481     /* If the path contains symlinks, get the real name */
00482     const QString realname = KStandardDirs::realFilePath(path);
00483 #else
00484     const QString realname = QDir::fromNativeSeparators(QDir(path).absolutePath());
00485 #endif
00486 
00487     int max = 0;
00488     KMountPoint::Ptr result;
00489     for (const_iterator it = begin(); it != end(); ++it) {
00490         const QString mountpoint = (*it)->d->mountPoint;
00491         const int length = mountpoint.length();
00492         if (realname.startsWith(mountpoint) && length > max) {
00493             max = length;
00494             result = *it;
00495             // keep iterating to check for a better match (bigger max)
00496         }
00497     }
00498     return result;
00499 }
00500 
00501 KMountPoint::Ptr KMountPoint::List::findByDevice(const QString& device) const
00502 {
00503     const QString realDevice = KStandardDirs::realFilePath(device);
00504     if (realDevice.isEmpty()) // d->device can be empty in the loop below, don't match empty with it
00505         return Ptr();
00506     for (const_iterator it = begin(); it != end(); ++it) {
00507         if ((*it)->d->device == realDevice ||
00508             (*it)->d->mountedFrom == realDevice)
00509             return *it;
00510     }
00511     return Ptr();
00512 }
00513 
00514 bool KMountPoint::probablySlow() const
00515 {
00516     bool nfs = d->mountType == QLatin1String("nfs");
00517     bool autofs = d->mountType == QLatin1String("autofs") || d->mountType == QLatin1String("subfs");
00518     //bool pid = d->mountPoint.contains(":(pid");
00519     // The "pid" thing was in kde3's KIO::probably_slow_mounted, with obscure logic
00520     // (looks like it used state from the previous line or something...)
00521     // This needs to be revised once we have a testcase or explanation about it.
00522     // But autofs works already, it shows nfs as mountType in mtab.
00523     if (nfs || autofs) {
00524         return true;
00525     }
00526     return false;
00527 }
00528 
00529 bool KMountPoint::testFileSystemFlag(FileSystemFlag flag) const
00530 {
00531     const bool isMsDos = ( d->mountType == QLatin1String("msdos") || d->mountType == QLatin1String("fat") || d->mountType == QLatin1String("vfat") );
00532     switch (flag)  {
00533     case SupportsChmod:
00534     case SupportsChown:
00535     case SupportsUTime:
00536     case SupportsSymlinks:
00537         return !isMsDos; // it's amazing the number of things FAT doesn't support :)
00538     case CaseInsensitive:
00539         return isMsDos;
00540     }
00541     return false;
00542 }
00543 

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal