• Skip to content
  • Skip to link menu
KDE 4.3 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          if (ft != 0) {
00312              QString options = QFile::decodeName(ft->fs_mntops);
00313              mp->d->mountOptions = options.split( ',' );
00314          } else {
00315              // TODO: get mount options if not mounted via fstab, see mounted[i].f_flags
00316          }
00317       }
00318 
00319       mp->d->finalizeCurrentMountPoint(infoNeeded);
00320       // TODO: Strip trailing '/' ?
00321       result.append(mp);
00322    }
00323 
00324 #elif defined(_AIX)
00325 
00326     struct vmount *mntctl_buffer;
00327     struct vmount *vm;
00328     char *mountedfrom;
00329     char *mountedto;
00330     int fsname_len, num;
00331     int buf_sz = 4096;
00332 
00333     mntctl_buffer = (struct vmount*)malloc(buf_sz);
00334     num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
00335     if (num == 0)
00336     {
00337     buf_sz = *(int*)mntctl_buffer;
00338     free(mntctl_buffer);
00339     mntctl_buffer = (struct vmount*)malloc(buf_sz);
00340     num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
00341     }
00342 
00343     if (num > 0)
00344     {
00345         /* iterate through items in the vmount structure: */
00346         vm = (struct vmount *)mntctl_buffer;
00347         for ( ; num > 0; --num )
00348         {
00349             /* get the name of the mounted file systems: */
00350             fsname_len = vmt2datasize(vm, VMT_STUB);
00351             mountedto     = (char*)malloc(fsname_len + 1);
00352         mountedto[fsname_len] = '\0';
00353             strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len);
00354 
00355             fsname_len = vmt2datasize(vm, VMT_OBJECT);
00356             mountedfrom     = (char*)malloc(fsname_len + 1);
00357         mountedfrom[fsname_len] = '\0';
00358             strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len);
00359 
00360         /* Look up the string for the file system type,
00361              * as listed in /etc/vfs.
00362              * ex.: nfs,jfs,afs,cdrfs,sfs,cachefs,nfs3,autofs
00363              */
00364             struct vfs_ent* ent = getvfsbytype(vm->vmt_gfstype);
00365 
00366             KMountPoint *mp = new KMountPoint;
00367             mp->d->mountedFrom = QFile::decodeName(mountedfrom);
00368             mp->d->mountPoint = QFile::decodeName(mountedto);
00369             mp->d->mountType = QFile::decodeName(ent->vfsent_name);
00370 
00371             free(mountedfrom);
00372             free(mountedto);
00373 
00374             if (infoNeeded & NeedMountOptions)
00375             {
00376               // TODO
00377             }
00378 
00379             mp->d->finalizeCurrentMountPoint(infoNeeded);
00380             result.append(mp);
00381 
00382             /* goto the next vmount structure: */
00383             vm = (struct vmount *)((char *)vm + vm->vmt_length);
00384         }
00385 
00386     endvfsent( );
00387     }
00388 
00389     free( mntctl_buffer );
00390 #elif defined(Q_WS_WIN)
00391     //nothing fancy with infoNeeded but it gets the job done
00392     DWORD bits = GetLogicalDrives();
00393     if(!bits)
00394         return result;
00395 
00396     for(int i = 0; i < 26; i++)
00397     {
00398         if(bits & (1 << i))
00399         {
00400             Ptr mp(new KMountPoint);
00401             mp->d->mountPoint = QString(QChar('A' + i) + QString(":/"));
00402             result.append(mp);
00403         }
00404     }
00405     
00406 #else
00407    STRUCT_SETMNTENT mnttab;
00408    if ((mnttab = SETMNTENT(MNTTAB, "r")) == 0)
00409       return result;
00410 
00411    STRUCT_MNTENT fe;
00412    while (GETMNTENT(mnttab, fe))
00413    {
00414       Ptr mp(new KMountPoint);
00415       mp->d->mountedFrom = QFile::decodeName(FSNAME(fe));
00416 
00417       mp->d->mountPoint = QFile::decodeName(MOUNTPOINT(fe));
00418       mp->d->mountType = QFile::decodeName(MOUNTTYPE(fe));
00419 
00420       //Devices using supermount have their device names in the mount options
00421       //instead of the device field. That's why we need to read the mount options
00422       if (infoNeeded & NeedMountOptions || (mp->d->mountType == "supermount"))
00423       {
00424          QString options = QFile::decodeName(MOUNTOPTIONS(fe));
00425          mp->d->mountOptions = options.split( ',' );
00426       }
00427       mp->d->finalizeCurrentMountPoint(infoNeeded);
00428 
00429       result.append(mp);
00430    }
00431    ENDMNTENT(mnttab);
00432 #endif
00433    return result;
00434 }
00435 
00436 QString KMountPoint::mountedFrom() const
00437 {
00438     return d->mountedFrom;
00439 }
00440 
00441 QString KMountPoint::realDeviceName() const
00442 {
00443     return d->device;
00444 }
00445 
00446 QString KMountPoint::mountPoint() const
00447 {
00448     return d->mountPoint;
00449 }
00450 
00451 QString KMountPoint::mountType() const
00452 {
00453     return d->mountType;
00454 }
00455 
00456 QStringList KMountPoint::mountOptions() const
00457 {
00458     return d->mountOptions;
00459 }
00460 
00461 KMountPoint::List::List()
00462     : QList<Ptr>()
00463 {
00464 }
00465 
00466 KMountPoint::Ptr KMountPoint::List::findByPath(const QString& path) const
00467 {
00468 #ifndef Q_WS_WIN
00469     /* If the path contains symlinks, get the real name */
00470     const QString realname = KStandardDirs::realFilePath(path);
00471 #else
00472     const QString realname = QDir::fromNativeSeparators(QDir(path).absolutePath());
00473 #endif
00474 
00475     int max = 0;
00476     KMountPoint::Ptr result;
00477     for (const_iterator it = begin(); it != end(); ++it) {
00478         const QString mountpoint = (*it)->d->mountPoint;
00479         const int length = mountpoint.length();
00480         if (realname.startsWith(mountpoint) && length > max) {
00481             max = length;
00482             result = *it;
00483             // keep iterating to check for a better match (bigger max)
00484         }
00485     }
00486     return result;
00487 }
00488 
00489 KMountPoint::Ptr KMountPoint::List::findByDevice(const QString& device) const
00490 {
00491     const QString realDevice = KStandardDirs::realFilePath(device);
00492     if (realDevice.isEmpty()) // d->device can be empty in the loop below, don't match empty with it
00493         return Ptr();
00494     for (const_iterator it = begin(); it != end(); ++it) {
00495         if ((*it)->d->device == realDevice ||
00496             (*it)->d->mountedFrom == realDevice)
00497             return *it;
00498     }
00499     return Ptr();
00500 }
00501 
00502 bool KMountPoint::probablySlow() const
00503 {
00504     bool nfs = d->mountType == "nfs";
00505     bool autofs = d->mountType == "autofs" || d->mountType == "subfs";
00506     //bool pid = d->mountPoint.contains(":(pid");
00507     // The "pid" thing was in kde3's KIO::probably_slow_mounted, with obscure logic
00508     // (looks like it used state from the previous line or something...)
00509     // This needs to be revised once we have a testcase or explanation about it.
00510     // But autofs works already, it shows nfs as mountType in mtab.
00511     if (nfs || autofs) {
00512         return true;
00513     }
00514     return false;
00515 }
00516 
00517 bool KMountPoint::testFileSystemFlag(FileSystemFlag flag) const
00518 {
00519     const bool isMsDos = ( d->mountType == "msdos" || d->mountType == "fat" || d->mountType == "vfat" );
00520     switch (flag)  {
00521     case SupportsChmod:
00522     case SupportsChown:
00523     case SupportsUTime:
00524     case SupportsSymlinks:
00525         return !isMsDos; // it's amazing the number of things FAT doesn't support :)
00526     case CaseInsensitive:
00527         return isMsDos;
00528     }
00529     return false;
00530 }
00531 

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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