• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

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

KIO

Skip menu "KIO"
  • Main Page
  • 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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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