• Skip to content
  • Skip to link menu
KDE 4.3 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     const char* txt = acl_to_text(acl);
00181     kDebug() << comment << txt;
00182     acl_free(txt);
00183 }
00184 #endif
00185 #endif
00186 
00187 static int getUidForName( const QString& name )
00188 {
00189     struct passwd *user = getpwnam( name.toLocal8Bit() );
00190     if ( user )
00191         return user->pw_uid;
00192     else
00193         return -1;
00194 }
00195 
00196 static int getGidForName( const QString& name )
00197 {
00198     struct group *group = getgrnam( name.toLocal8Bit() );
00199     if ( group )
00200         return group->gr_gid;
00201     else
00202         return -1;
00203 }
00204 #endif
00205 // ------------------ begin API implementation ------------
00206 
00207 unsigned short KACL::ownerPermissions() const
00208 {
00209 #ifdef HAVE_POSIX_ACL
00210     return entryToPermissions( entryForTag( d->m_acl, ACL_USER_OBJ ) );
00211 #else
00212     return 0;
00213 #endif
00214 }
00215 
00216 bool KACL::setOwnerPermissions( unsigned short v )
00217 {
00218 #ifdef HAVE_POSIX_ACL
00219     permissionsToEntry( entryForTag( d->m_acl, ACL_USER_OBJ ), v );
00220 #else
00221     Q_UNUSED( v );
00222 #endif
00223     return true;
00224 }
00225 
00226 unsigned short KACL::owningGroupPermissions() const
00227 {
00228 #ifdef HAVE_POSIX_ACL
00229     return entryToPermissions( entryForTag( d->m_acl, ACL_GROUP_OBJ ) );
00230 #else
00231     return 0;
00232 #endif
00233 }
00234 
00235 bool KACL::setOwningGroupPermissions( unsigned short v )
00236 {
00237 #ifdef HAVE_POSIX_ACL
00238     permissionsToEntry( entryForTag( d->m_acl, ACL_GROUP_OBJ ), v );
00239 #else
00240     Q_UNUSED( v );
00241 #endif
00242     return true;
00243 }
00244 
00245 unsigned short KACL::othersPermissions() const
00246 {
00247 #ifdef HAVE_POSIX_ACL
00248     return entryToPermissions( entryForTag( d->m_acl, ACL_OTHER ) );
00249 #else
00250     return 0;
00251 #endif
00252 }
00253 
00254 bool KACL::setOthersPermissions( unsigned short v )
00255 {
00256 #ifdef HAVE_POSIX_ACL
00257     permissionsToEntry( entryForTag( d->m_acl, ACL_OTHER ), v );
00258 #else
00259     Q_UNUSED( v );
00260 #endif
00261     return true;
00262 }
00263 
00264 mode_t KACL::basePermissions() const
00265 {
00266     mode_t perms( 0 );
00267 #ifdef HAVE_POSIX_ACL
00268     if ( ownerPermissions() & ACL_READ ) perms |= S_IRUSR;
00269     if ( ownerPermissions() & ACL_WRITE ) perms |= S_IWUSR;
00270     if ( ownerPermissions() & ACL_EXECUTE ) perms |= S_IXUSR;
00271     if ( owningGroupPermissions() & ACL_READ ) perms |= S_IRGRP;
00272     if ( owningGroupPermissions() & ACL_WRITE ) perms |= S_IWGRP;
00273     if ( owningGroupPermissions() & ACL_EXECUTE ) perms |= S_IXGRP;
00274     if ( othersPermissions() & ACL_READ ) perms |= S_IROTH;
00275     if ( othersPermissions() & ACL_WRITE ) perms |= S_IWOTH;
00276     if ( othersPermissions() & ACL_EXECUTE ) perms |= S_IXOTH;
00277 #endif
00278    return perms;
00279 }
00280 
00281 unsigned short KACL::maskPermissions( bool &exists ) const
00282 {
00283     exists = true;
00284 #ifdef HAVE_POSIX_ACL
00285     acl_entry_t entry = entryForTag( d->m_acl, ACL_MASK );
00286     if ( entry == 0 ) {
00287         exists = false;
00288         return 0;
00289     }
00290     return entryToPermissions( entry );
00291 #else
00292     return 0;
00293 #endif
00294 }
00295 
00296 #ifdef HAVE_POSIX_ACL
00297 bool KACL::KACLPrivate::setMaskPermissions( unsigned short v )
00298 {
00299     acl_entry_t entry = entryForTag( m_acl, ACL_MASK );
00300     if ( entry == 0 ) {
00301         acl_create_entry( &m_acl, &entry );
00302         acl_set_tag_type( entry, ACL_MASK );
00303     }
00304     permissionsToEntry( entry, v );
00305     return true;
00306 }
00307 #endif
00308 
00309 bool KACL::setMaskPermissions( unsigned short v )
00310 {
00311 #ifdef HAVE_POSIX_ACL
00312     return d->setMaskPermissions( v );
00313 #else
00314     Q_UNUSED( v );
00315     return true;
00316 #endif
00317 }
00318 
00319 /**************************
00320  * Deal with named users  *
00321  **************************/
00322 unsigned short KACL::namedUserPermissions( const QString& name, bool *exists ) const
00323 {
00324 #ifdef HAVE_POSIX_ACL
00325     acl_entry_t entry;
00326     uid_t id;
00327     *exists = false;
00328     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00329     while ( ret == 1 ) {
00330         acl_tag_t currentTag;
00331         acl_get_tag_type( entry, &currentTag );
00332         if ( currentTag ==  ACL_USER ) {
00333             id = *( (uid_t*) acl_get_qualifier( entry ) );
00334             if ( d->getUserName( id ) == name ) {
00335                 *exists = true;
00336                 return entryToPermissions( entry );
00337             }
00338         }
00339         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00340     }
00341 #else
00342     Q_UNUSED( name );
00343     Q_UNUSED( exists );
00344 #endif
00345     return 0;
00346 }
00347 
00348 #ifdef HAVE_POSIX_ACL
00349 bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type )
00350 {
00351     bool allIsWell = true;
00352     acl_t newACL = acl_dup( m_acl );
00353     acl_entry_t entry;
00354     bool createdNewEntry = false;
00355     bool found = false;
00356     int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00357     while ( ret == 1 ) {
00358         acl_tag_t currentTag;
00359         acl_get_tag_type( entry, &currentTag );
00360         if ( currentTag == type ) {
00361             int id = * (int*)acl_get_qualifier( entry );
00362             const QString entryName = type == ACL_USER? getUserName( id ): getGroupName( id );
00363             if ( entryName == name ) {
00364               // found him, update
00365               permissionsToEntry( entry, permissions );
00366               found = true;
00367               break;
00368             }
00369         }
00370         ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00371     }
00372     if ( !found ) {
00373         acl_create_entry( &newACL, &entry );
00374         acl_set_tag_type(  entry, type );
00375         int id = type == ACL_USER? getUidForName( name ): getGidForName( name );
00376         if ( id == -1 ||  acl_set_qualifier( entry, &id ) != 0 ) {
00377             acl_delete_entry( newACL, entry );
00378             allIsWell = false;
00379         } else {
00380             permissionsToEntry( entry, permissions );
00381             createdNewEntry = true;
00382         }
00383     }
00384     if ( allIsWell && createdNewEntry ) {
00385         // 23.1.1 of 1003.1e states that as soon as there is a named user or
00386         // named group entry, there needs to be a mask entry as well, so add
00387         // one, if the user hasn't explicitly set one.
00388         if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00389             acl_calc_mask( &newACL );
00390         }
00391     }
00392 
00393     if ( !allIsWell || acl_valid( newACL ) != 0 ) {
00394         acl_free( newACL );
00395         allIsWell = false;
00396     } else {
00397         acl_free( m_acl );
00398         m_acl = newACL;
00399     }
00400     return allIsWell;
00401 }
00402 #endif
00403 
00404 bool KACL::setNamedUserPermissions( const QString& name, unsigned short permissions )
00405 {
00406 #ifdef HAVE_POSIX_ACL
00407     return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER );
00408 #else
00409     Q_UNUSED( name );
00410     Q_UNUSED( permissions );
00411     return true;
00412 #endif
00413 }
00414 
00415 ACLUserPermissionsList KACL::allUserPermissions() const
00416 {
00417     ACLUserPermissionsList list;
00418 #ifdef HAVE_POSIX_ACL
00419     acl_entry_t entry;
00420     uid_t id;
00421     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00422     while ( ret == 1 ) {
00423         acl_tag_t currentTag;
00424         acl_get_tag_type( entry, &currentTag );
00425         if ( currentTag ==  ACL_USER ) {
00426             id = *( (uid_t*) acl_get_qualifier( entry ) );
00427             QString name = d->getUserName( id );
00428             unsigned short permissions = entryToPermissions( entry );
00429             ACLUserPermissions pair = qMakePair( name, permissions );
00430             list.append( pair );
00431         }
00432         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00433     }
00434 #endif
00435     return list;
00436 }
00437 
00438 #ifdef HAVE_POSIX_ACL
00439 bool KACL::KACLPrivate::setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type )
00440 {
00441     bool allIsWell = true;
00442     bool atLeastOneUserOrGroup = false;
00443 
00444     // make working copy, in case something goes wrong
00445     acl_t newACL = acl_dup( m_acl );
00446     acl_entry_t entry;
00447 
00448 //printACL( newACL, "Before cleaning: " );
00449     // clear user entries
00450     int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00451     while ( ret == 1 ) {
00452         acl_tag_t currentTag;
00453         acl_get_tag_type( entry, &currentTag );
00454         if ( currentTag ==  type ) {
00455             acl_delete_entry( newACL, entry );
00456             // we have to start from the beginning, the iterator is
00457             // invalidated, on deletion
00458             ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00459         } else {
00460             ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00461         }
00462     }
00463 //printACL( newACL, "After cleaning out entries: " );
00464 
00465     // now add the entries from the list
00466     QList< QPair<QString, unsigned short> >::const_iterator it = list.constBegin();
00467     while ( it != list.constEnd() ) {
00468         acl_create_entry( &newACL, &entry );
00469         acl_set_tag_type( entry, type );
00470         int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first );
00471         if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00472             // user or group doesn't exist => error
00473             acl_delete_entry( newACL, entry );
00474             allIsWell = false;
00475             break;
00476         } else {
00477             permissionsToEntry( entry, (*it).second );
00478             atLeastOneUserOrGroup = true;
00479         }
00480         ++it;
00481     }
00482 //printACL( newACL, "After adding entries: " );
00483     if ( allIsWell && atLeastOneUserOrGroup ) {
00484         // 23.1.1 of 1003.1e states that as soon as there is a named user or
00485         // named group entry, there needs to be a mask entry as well, so add
00486         // one, if the user hasn't explicitly set one.
00487         if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00488             acl_calc_mask( &newACL );
00489         }
00490     }
00491     if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) {
00492         acl_free( m_acl );
00493         m_acl = newACL;
00494     } else {
00495         acl_free( newACL );
00496     }
00497     return allIsWell;
00498 }
00499 #endif
00500 
00501 bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users )
00502 {
00503 #ifdef HAVE_POSIX_ACL
00504     return d->setAllUsersOrGroups( users, ACL_USER );
00505 #else
00506     Q_UNUSED( users );
00507     return true;
00508 #endif
00509 }
00510 
00511 
00512 /**************************
00513  * Deal with named groups  *
00514  **************************/
00515 
00516 unsigned short KACL::namedGroupPermissions( const QString& name, bool *exists ) const
00517 {
00518     *exists = false;
00519 #ifdef HAVE_POSIX_ACL
00520     acl_entry_t entry;
00521     gid_t id;
00522     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00523     while ( ret == 1 ) {
00524         acl_tag_t currentTag;
00525         acl_get_tag_type( entry, &currentTag );
00526         if ( currentTag ==  ACL_GROUP ) {
00527             id = *( (gid_t*) acl_get_qualifier( entry ) );
00528             if ( d->getGroupName( id ) == name ) {
00529                 *exists = true;
00530                 return entryToPermissions( entry );
00531             }
00532         }
00533         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00534     }
00535 #else
00536     Q_UNUSED( name );
00537 #endif
00538     return 0;
00539 }
00540 
00541 bool KACL::setNamedGroupPermissions( const QString& name, unsigned short permissions )
00542 {
00543 #ifdef HAVE_POSIX_ACL
00544     return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP );
00545 #else
00546     Q_UNUSED( name );
00547     Q_UNUSED( permissions );
00548     return true;
00549 #endif
00550 }
00551 
00552 
00553 ACLGroupPermissionsList KACL::allGroupPermissions() const
00554 {
00555     ACLGroupPermissionsList list;
00556 #ifdef HAVE_POSIX_ACL
00557     acl_entry_t entry;
00558     gid_t id;
00559     int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00560     while ( ret == 1 ) {
00561         acl_tag_t currentTag;
00562         acl_get_tag_type( entry, &currentTag );
00563         if ( currentTag ==  ACL_GROUP ) {
00564             id = *( (gid_t*) acl_get_qualifier( entry ) );
00565             QString name = d->getGroupName( id );
00566             unsigned short permissions = entryToPermissions( entry );
00567             ACLGroupPermissions pair = qMakePair( name, permissions );
00568             list.append( pair );
00569         }
00570         ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00571     }
00572 #endif
00573     return list;
00574 }
00575 
00576 bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups )
00577 {
00578 #ifdef HAVE_POSIX_ACL
00579     return d->setAllUsersOrGroups( groups, ACL_GROUP );
00580 #else
00581     Q_UNUSED( groups );
00582     return true;
00583 #endif
00584 }
00585 
00586 /**************************
00587  * from and to string     *
00588  **************************/
00589 
00590 bool KACL::setACL( const QString &aclStr )
00591 {
00592     bool ret = false;
00593 #ifdef HAVE_POSIX_ACL
00594     acl_t temp = acl_from_text( aclStr.toLatin1() );
00595     if ( acl_valid( temp ) != 0 ) {
00596         // TODO errno is set, what to do with it here?
00597         acl_free( temp );
00598     } else {
00599         if ( d->m_acl )
00600             acl_free( d->m_acl );
00601         d->m_acl = temp;
00602         ret = true;
00603     }
00604 #else
00605     Q_UNUSED( aclStr );
00606 #endif
00607     return ret;
00608 }
00609 
00610 QString KACL::asString() const
00611 {
00612 #ifdef HAVE_POSIX_ACL
00613     ssize_t size = 0;
00614     char* txt = acl_to_text(d->m_acl, &size);
00615     const QString ret = QString::fromLatin1(txt, size);
00616     acl_free(txt);
00617     return ret;
00618 #else
00619     return QString();
00620 #endif
00621 }
00622 
00623 
00624 // helpers
00625 
00626 #ifdef HAVE_POSIX_ACL
00627 QString KACL::KACLPrivate::getUserName( uid_t uid ) const
00628 {
00629     if ( !m_usercache.contains( uid ) ) {
00630         struct passwd *user = getpwuid( uid );
00631         if ( user ) {
00632             m_usercache.insert( uid, QString::fromLatin1(user->pw_name) );
00633         }
00634         else
00635             return QString::number( uid );
00636     }
00637     return m_usercache[uid];
00638 }
00639 
00640 
00641 QString KACL::KACLPrivate::getGroupName( gid_t gid ) const
00642 {
00643     if ( !m_groupcache.contains( gid ) ) {
00644         struct group *grp = getgrgid( gid );
00645         if ( grp ) {
00646             m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
00647         }
00648         else
00649             return QString::number( gid );
00650     }
00651     return m_groupcache[gid];
00652 }
00653 #endif
00654 
00655 void KACL::virtual_hook( int, void* )
00656 { /*BASE::virtual_hook( id, data );*/ }
00657 
00658 QDataStream & operator<< ( QDataStream & s, const KACL & a )
00659 {
00660     s << a.asString();
00661     return s;
00662 }
00663 
00664 QDataStream & operator>> ( QDataStream & s, KACL & a )
00665 {
00666     QString str;
00667     s >> str;
00668     a.setACL( str );
00669     return s;
00670 }
00671 
00672 // 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
  • 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