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

KIO

kacl.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2005 - 2007 Till Adam <adam@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 // $Id: kacl.cpp 424977 2005-06-13 15:13:22Z tilladam $
00020 
00021 #include "kacl.h"
00022 
00023 #include <config-acl.h>
00024 
00025 #include <sys/types.h>
00026 #include <pwd.h>
00027 #include <grp.h>
00028 #include <sys/stat.h>
00029 #ifdef HAVE_POSIX_ACL
00030 #include <sys/acl.h>
00031 #include <acl/libacl.h>
00032 #endif
00033 #include <QHash>
00034 
00035 #include <kdebug.h>
00036 
00037 #include <QList>
00038 #include <QPair>
00039 
00040 
00041 class KACL::KACLPrivate {
00042 public:
00043     KACLPrivate() : m_acl( 0 ) {}
00044 #ifdef HAVE_POSIX_ACL
00045     KACLPrivate( acl_t acl )
00046         : m_acl( acl ) {}
00047     ~KACLPrivate() { if ( m_acl ) acl_free( m_acl ); }
00048 #endif
00049     // helpers
00050 #ifdef HAVE_POSIX_ACL
00051     bool setMaskPermissions( unsigned short v );
00052     QString getUserName( uid_t uid ) const;
00053     QString getGroupName( gid_t gid ) const;
00054     bool setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type );
00055     bool setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type );
00056 
00057     acl_t m_acl;
00058 #else
00059     int m_acl;
00060 #endif
00061     mutable QHash<uid_t, QString> m_usercache;
00062     mutable QHash<gid_t, QString> m_groupcache;
00063 };
00064 
00065 KACL::KACL( const QString &aclString )
00066     : d( new KACLPrivate )
00067 {
00068     setACL( aclString );
00069 }
00070 
00071 KACL::KACL( mode_t basePermissions )
00072 #ifdef HAVE_POSIX_ACL
00073     : d( new KACLPrivate( acl_from_mode( basePermissions ) ) )
00074 #else
00075     : d( new KACLPrivate )
00076 #endif
00077 {
00078 #ifndef HAVE_POSIX_ACL
00079     Q_UNUSED( basePermissions );
00080 #endif
00081 }
00082 
00083 KACL::KACL()
00084     : d( new KACLPrivate )
00085 {
00086 }
00087 
00088 KACL::KACL( const KACL& rhs )
00089     : d( new KACLPrivate )
00090 {
00091     setACL( rhs.asString() );
00092 }
00093 
00094 KACL::~KACL()
00095 {
00096     delete d;
00097 }
00098 
00099 KACL& KACL::operator=( const KACL& rhs )
00100 {
00101     if ( this != &rhs )
00102       setACL( rhs.asString() );
00103     return *this;
00104 }
00105 
00106 bool KACL::operator==( const KACL& rhs ) const {
00107 #ifdef HAVE_POSIX_ACL
00108     return ( acl_cmp( d->m_acl, rhs.d->m_acl ) == 0 );
00109 #else
00110     Q_UNUSED( rhs );
00111     return true;
00112 #endif
00113 }
00114 
00115 bool KACL::operator!=( const KACL& rhs ) const
00116 {
00117     return !operator==( rhs );
00118 }
00119 
00120 bool KACL::isValid() const
00121 {
00122     bool valid = false;
00123 #ifdef HAVE_POSIX_ACL
00124     if ( d->m_acl ) {
00125         valid = ( acl_valid( d->m_acl ) == 0 );
00126     }
00127 #endif
00128     return valid;
00129 }
00130 
00131 bool KACL::isExtended() const
00132 {
00133 #ifdef HAVE_POSIX_ACL
00134     return ( acl_equiv_mode( d->m_acl, NULL ) != 0 );
00135 #else
00136     return false;
00137 #endif
00138 }
00139 
00140 #ifdef HAVE_POSIX_ACL
00141 static acl_entry_t entryForTag( acl_t acl, acl_tag_t tag )
00142 {
00143     acl_entry_t entry;
00144     int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry );
00145     while ( ret == 1 ) {
00146         acl_tag_t currentTag;
00147         acl_get_tag_type( entry, &currentTag );
00148         if ( currentTag == tag )
00149             return entry;
00150         ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry );
00151     }
00152     return 0;
00153 }
00154 
00155 static unsigned short entryToPermissions( acl_entry_t entry )
00156 {
00157     if ( entry == 0 ) return 0;
00158     acl_permset_t permset;
00159     if ( acl_get_permset( entry, &permset ) != 0 ) return 0;
00160     return( acl_get_perm( permset, ACL_READ ) << 2 |
00161             acl_get_perm( permset, ACL_WRITE ) << 1 |
00162             acl_get_perm( permset, ACL_EXECUTE ) );
00163 }
00164 
00165 static void permissionsToEntry( acl_entry_t entry, unsigned short v )
00166 {
00167     if ( entry == 0 ) return;
00168     acl_permset_t permset;
00169     if ( acl_get_permset( entry, &permset ) != 0 ) return;
00170     acl_clear_perms( permset );
00171     if ( v & 4 ) acl_add_perm( permset, ACL_READ );
00172     if ( v & 2 ) acl_add_perm( permset, ACL_WRITE );
00173     if ( v & 1 ) acl_add_perm( permset, ACL_EXECUTE );
00174 }
00175 
00176 #ifdef HAVE_POSIX_ACL
00177 #if 0
00178 static void printACL( acl_t acl, const QString &comment )
00179 {
00180     ssize_t size = acl_size( acl );
00181     kDebug() << comment << acl_to_text( acl, &size );
00182 }
00183 #endif
00184 #endif
00185 
00186 static int getUidForName( const QString& name )
00187 {
00188     struct passwd *user = getpwnam( name.toLocal8Bit() );
00189     if ( user )
00190         return user->pw_uid;
00191     else
00192         return -1;
00193 }
00194 
00195 static int getGidForName( const QString& name )
00196 {
00197     struct group *group = getgrnam( name.toLocal8Bit() );
00198     if ( group )
00199         return group->gr_gid;
00200     else
00201         return -1;
00202 }
00203 #endif
00204 // ------------------ begin API implementation ------------
00205 
00206 unsigned short KACL::ownerPermissions() const
00207 {
00208 #ifdef HAVE_POSIX_ACL
00209     return entryToPermissions( entryForTag( d->m_acl, ACL_USER_OBJ ) );
00210 #else
00211     return 0;
00212 #endif
00213 }
00214 
00215 bool KACL::setOwnerPermissions( unsigned short v )
00216 {
00217 #ifdef HAVE_POSIX_ACL
00218     permissionsToEntry( entryForTag( d->m_acl, ACL_USER_OBJ ), v );
00219 #else
00220     Q_UNUSED( v );
00221 #endif
00222     return true;
00223 }
00224 
00225 unsigned short KACL::owningGroupPermissions() const
00226 {
00227 #ifdef HAVE_POSIX_ACL
00228     return entryToPermissions( entryForTag( d->m_acl, ACL_GROUP_OBJ ) );
00229 #else
00230     return 0;
00231 #endif
00232 }
00233 
00234 bool KACL::setOwningGroupPermissions( unsigned short v )
00235 {
00236 #ifdef HAVE_POSIX_ACL
00237     permissionsToEntry( entryForTag( d->m_acl, ACL_GROUP_OBJ ), v );
00238 #else
00239     Q_UNUSED( v );
00240 #endif
00241     return true;
00242 }
00243 
00244 unsigned short KACL::othersPermissions() const
00245 {
00246 #ifdef HAVE_POSIX_ACL
00247     return entryToPermissions( entryForTag( d->m_acl, ACL_OTHER ) );
00248 #else
00249     return 0;
00250 #endif
00251 }
00252 
00253 bool KACL::setOthersPermissions( unsigned short v )
00254 {
00255 #ifdef HAVE_POSIX_ACL
00256     permissionsToEntry( entryForTag( d->m_acl, ACL_OTHER ), v );
00257 #else
00258     Q_UNUSED( v );
00259 #endif
00260     return true;
00261 }
00262 
00263 mode_t KACL::basePermissions() const
00264 {
00265     mode_t perms( 0 );
00266 #ifdef HAVE_POSIX_ACL
00267     if ( ownerPermissions() & ACL_READ ) perms |= S_IRUSR;
00268     if ( ownerPermissions() & ACL_WRITE ) perms |= S_IWUSR;
00269     if ( ownerPermissions() & ACL_EXECUTE ) perms |= S_IXUSR;
00270     if ( owningGroupPermissions() & ACL_READ ) perms |= S_IRGRP;
00271     if ( owningGroupPermissions() & ACL_WRITE ) perms |= S_IWGRP;
00272     if ( owningGroupPermissions() & ACL_EXECUTE ) perms |= S_IXGRP;
00273     if ( othersPermissions() & ACL_READ ) perms |= S_IROTH;
00274     if ( othersPermissions() & ACL_WRITE ) perms |= S_IWOTH;
00275     if ( othersPermissions() & ACL_EXECUTE ) perms |= S_IXOTH;
00276 #endif
00277    return perms;
00278 }
00279 
00280 unsigned short KACL::maskPermissions( bool &exists ) const
00281 {
00282     exists = true;
00283 #ifdef HAVE_POSIX_ACL
00284     acl_entry_t entry = entryForTag( d->m_acl, ACL_MASK );
00285     if ( entry == 0 ) {
00286         exists = false;
00287         return 0;
00288     }
00289     return entryToPermissions( entry );
00290 #else
00291     return 0;
00292 #endif
00293 }
00294 
00295 #ifdef HAVE_POSIX_ACL
00296 bool KACL::KACLPrivate::setMaskPermissions( unsigned short v )
00297 {
00298     acl_entry_t entry = entryForTag( m_acl, ACL_MASK );
00299     if ( entry == 0 ) {
00300         acl_create_entry( &m_acl, &entry );
00301         acl_set_tag_type( entry, ACL_MASK );
00302     }
00303     permissionsToEntry( entry, v );
00304     return true;
00305 }
00306 #endif
00307 
00308 bool KACL::setMaskPermissions( unsigned short v )
00309 {
00310 #ifdef HAVE_POSIX_ACL
00311     return d->setMaskPermissions( v );
00312 #else
00313     Q_UNUSED( v );
00314     return true;
00315 #endif
00316 }
00317 
00318 /**************************
00319  * Deal with named users  *
00320  **************************/
00321 unsigned short KACL::namedUserPermissions( const QString& name, bool *exists ) const
00322 {
00323 #ifdef HAVE_POSIX_ACL
00324     acl_entry_t entry;
00325     uid_t id;
00326     *exists = false;
00327     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00328     while ( ret == 1 ) {
00329         acl_tag_t currentTag;
00330         acl_get_tag_type( entry, &currentTag );
00331         if ( currentTag ==  ACL_USER ) {
00332             id = *( (uid_t*) acl_get_qualifier( entry ) );
00333             if ( d->getUserName( id ) == name ) {
00334                 *exists = true;
00335                 return entryToPermissions( entry );
00336             }
00337         }
00338         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00339     }
00340 #else
00341     Q_UNUSED( name );
00342     Q_UNUSED( exists );
00343 #endif
00344     return 0;
00345 }
00346 
00347 #ifdef HAVE_POSIX_ACL
00348 bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type )
00349 {
00350     bool allIsWell = true;
00351     acl_t newACL = acl_dup( m_acl );
00352     acl_entry_t entry;
00353     bool createdNewEntry = false;
00354     bool found = false;
00355     int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00356     while ( ret == 1 ) {
00357         acl_tag_t currentTag;
00358         acl_get_tag_type( entry, &currentTag );
00359         if ( currentTag == type ) {
00360             int id = * (int*)acl_get_qualifier( entry );
00361             const QString entryName = type == ACL_USER? getUserName( id ): getGroupName( id );
00362             if ( entryName == name ) {
00363               // found him, update
00364               permissionsToEntry( entry, permissions );
00365               found = true;
00366               break;
00367             }
00368         }
00369         ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00370     }
00371     if ( !found ) {
00372         acl_create_entry( &newACL, &entry );
00373         acl_set_tag_type(  entry, type );
00374         int id = type == ACL_USER? getUidForName( name ): getGidForName( name );
00375         if ( id == -1 ||  acl_set_qualifier( entry, &id ) != 0 ) {
00376             acl_delete_entry( newACL, entry );
00377             allIsWell = false;
00378         } else {
00379             permissionsToEntry( entry, permissions );
00380             createdNewEntry = true;
00381         }
00382     }
00383     if ( allIsWell && createdNewEntry ) {
00384         // 23.1.1 of 1003.1e states that as soon as there is a named user or
00385         // named group entry, there needs to be a mask entry as well, so add
00386         // one, if the user hasn't explicitly set one.
00387         if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00388             acl_calc_mask( &newACL );
00389         }
00390     }
00391 
00392     if ( !allIsWell || acl_valid( newACL ) != 0 ) {
00393         acl_free( newACL );
00394         allIsWell = false;
00395     } else {
00396         acl_free( m_acl );
00397         m_acl = newACL;
00398     }
00399     return allIsWell;
00400 }
00401 #endif
00402 
00403 bool KACL::setNamedUserPermissions( const QString& name, unsigned short permissions )
00404 {
00405 #ifdef HAVE_POSIX_ACL
00406     return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER );
00407 #else
00408     Q_UNUSED( name );
00409     Q_UNUSED( permissions );
00410     return true;
00411 #endif
00412 }
00413 
00414 ACLUserPermissionsList KACL::allUserPermissions() const
00415 {
00416     ACLUserPermissionsList list;
00417 #ifdef HAVE_POSIX_ACL
00418     acl_entry_t entry;
00419     uid_t id;
00420     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00421     while ( ret == 1 ) {
00422         acl_tag_t currentTag;
00423         acl_get_tag_type( entry, &currentTag );
00424         if ( currentTag ==  ACL_USER ) {
00425             id = *( (uid_t*) acl_get_qualifier( entry ) );
00426             QString name = d->getUserName( id );
00427             unsigned short permissions = entryToPermissions( entry );
00428             ACLUserPermissions pair = qMakePair( name, permissions );
00429             list.append( pair );
00430         }
00431         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00432     }
00433 #endif
00434     return list;
00435 }
00436 
00437 #ifdef HAVE_POSIX_ACL
00438 bool KACL::KACLPrivate::setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type )
00439 {
00440     bool allIsWell = true;
00441     bool atLeastOneUserOrGroup = false;
00442 
00443     // make working copy, in case something goes wrong
00444     acl_t newACL = acl_dup( m_acl );
00445     acl_entry_t entry;
00446 
00447 //printACL( newACL, "Before cleaning: " );
00448     // clear user entries
00449     int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00450     while ( ret == 1 ) {
00451         acl_tag_t currentTag;
00452         acl_get_tag_type( entry, &currentTag );
00453         if ( currentTag ==  type ) {
00454             acl_delete_entry( newACL, entry );
00455             // we have to start from the beginning, the iterator is
00456             // invalidated, on deletion
00457             ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00458         } else {
00459             ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00460         }
00461     }
00462 //printACL( newACL, "After cleaning out entries: " );
00463 
00464     // now add the entries from the list
00465     QList< QPair<QString, unsigned short> >::const_iterator it = list.constBegin();
00466     while ( it != list.constEnd() ) {
00467         acl_create_entry( &newACL, &entry );
00468         acl_set_tag_type( entry, type );
00469         int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first );
00470         if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00471             // user or group doesn't exist => error
00472             acl_delete_entry( newACL, entry );
00473             allIsWell = false;
00474             break;
00475         } else {
00476             permissionsToEntry( entry, (*it).second );
00477             atLeastOneUserOrGroup = true;
00478         }
00479         ++it;
00480     }
00481 //printACL( newACL, "After adding entries: " );
00482     if ( allIsWell && atLeastOneUserOrGroup ) {
00483         // 23.1.1 of 1003.1e states that as soon as there is a named user or
00484         // named group entry, there needs to be a mask entry as well, so add
00485         // one, if the user hasn't explicitly set one.
00486         if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00487             acl_calc_mask( &newACL );
00488         }
00489     }
00490     if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) {
00491         acl_free( m_acl );
00492         m_acl = newACL;
00493     } else {
00494         acl_free( newACL );
00495     }
00496     return allIsWell;
00497 }
00498 #endif
00499 
00500 bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users )
00501 {
00502 #ifdef HAVE_POSIX_ACL
00503     return d->setAllUsersOrGroups( users, ACL_USER );
00504 #else
00505     Q_UNUSED( users );
00506     return true;
00507 #endif
00508 }
00509 
00510 
00511 /**************************
00512  * Deal with named groups  *
00513  **************************/
00514 
00515 unsigned short KACL::namedGroupPermissions( const QString& name, bool *exists ) const
00516 {
00517     *exists = false;
00518 #ifdef HAVE_POSIX_ACL
00519     acl_entry_t entry;
00520     gid_t id;
00521     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00522     while ( ret == 1 ) {
00523         acl_tag_t currentTag;
00524         acl_get_tag_type( entry, &currentTag );
00525         if ( currentTag ==  ACL_GROUP ) {
00526             id = *( (gid_t*) acl_get_qualifier( entry ) );
00527             if ( d->getGroupName( id ) == name ) {
00528                 *exists = true;
00529                 return entryToPermissions( entry );
00530             }
00531         }
00532         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00533     }
00534 #else
00535     Q_UNUSED( name );
00536 #endif
00537     return 0;
00538 }
00539 
00540 bool KACL::setNamedGroupPermissions( const QString& name, unsigned short permissions )
00541 {
00542 #ifdef HAVE_POSIX_ACL
00543     return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP );
00544 #else
00545     Q_UNUSED( name );
00546     Q_UNUSED( permissions );
00547     return true;
00548 #endif
00549 }
00550 
00551 
00552 ACLGroupPermissionsList KACL::allGroupPermissions() const
00553 {
00554     ACLGroupPermissionsList list;
00555 #ifdef HAVE_POSIX_ACL
00556     acl_entry_t entry;
00557     gid_t id;
00558     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00559     while ( ret == 1 ) {
00560         acl_tag_t currentTag;
00561         acl_get_tag_type( entry, &currentTag );
00562         if ( currentTag ==  ACL_GROUP ) {
00563             id = *( (gid_t*) acl_get_qualifier( entry ) );
00564             QString name = d->getGroupName( id );
00565             unsigned short permissions = entryToPermissions( entry );
00566             ACLGroupPermissions pair = qMakePair( name, permissions );
00567             list.append( pair );
00568         }
00569         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00570     }
00571 #endif
00572     return list;
00573 }
00574 
00575 bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups )
00576 {
00577 #ifdef HAVE_POSIX_ACL
00578     return d->setAllUsersOrGroups( groups, ACL_GROUP );
00579 #else
00580     Q_UNUSED( groups );
00581     return true;
00582 #endif
00583 }
00584 
00585 /**************************
00586  * from and to string     *
00587  **************************/
00588 
00589 bool KACL::setACL( const QString &aclStr )
00590 {
00591     bool ret = false;
00592 #ifdef HAVE_POSIX_ACL
00593     acl_t temp = acl_from_text( aclStr.toLatin1() );
00594     if ( acl_valid( temp ) != 0 ) {
00595         // TODO errno is set, what to do with it here?
00596         acl_free( temp );
00597     } else {
00598         if ( d->m_acl )
00599             acl_free( d->m_acl );
00600         d->m_acl = temp;
00601         ret = true;
00602     }
00603 #else
00604     Q_UNUSED( aclStr );
00605 #endif
00606     return ret;
00607 }
00608 
00609 QString KACL::asString() const
00610 {
00611 #ifdef HAVE_POSIX_ACL
00612     ssize_t size = acl_size( d->m_acl );
00613     return QString::fromLatin1( acl_to_text( d->m_acl, &size ) );
00614 #else
00615     return QString();
00616 #endif
00617 }
00618 
00619 
00620 // helpers
00621 
00622 #ifdef HAVE_POSIX_ACL
00623 QString KACL::KACLPrivate::getUserName( uid_t uid ) const
00624 {
00625     if ( !m_usercache.contains( uid ) ) {
00626         struct passwd *user = getpwuid( uid );
00627         if ( user ) {
00628             m_usercache.insert( uid, QString::fromLatin1(user->pw_name) );
00629         }
00630         else
00631             return QString::number( uid );
00632     }
00633     return m_usercache[uid];
00634 }
00635 
00636 
00637 QString KACL::KACLPrivate::getGroupName( gid_t gid ) const
00638 {
00639     if ( !m_groupcache.contains( gid ) ) {
00640         struct group *grp = getgrgid( gid );
00641         if ( grp ) {
00642             m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
00643         }
00644         else
00645             return QString::number( gid );
00646     }
00647     return m_groupcache[gid];
00648 }
00649 #endif
00650 
00651 void KACL::virtual_hook( int, void* )
00652 { /*BASE::virtual_hook( id, data );*/ }
00653 
00654 QDataStream & operator<< ( QDataStream & s, const KACL & a )
00655 {
00656     s << a.asString();
00657     return s;
00658 }
00659 
00660 QDataStream & operator>> ( QDataStream & s, KACL & a )
00661 {
00662     QString str;
00663     s >> str;
00664     a.setACL( str );
00665     return s;
00666 }
00667 
00668 // vim:set ts=8 sw=4:

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