From kfm-devel Sun Aug 07 09:56:36 2005 From: Till Adam Date: Sun, 07 Aug 2005 09:56:36 +0000 To: kfm-devel Subject: [PATCH] Support for POSIX ACL in kioslave/file and kio/kio Message-Id: <200508071156.44379.adam () kde ! org> X-MARC-Message: https://marc.info/?l=kfm-devel&m=112342156412359 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--nextPart1492079.yORxeDNXAC" --nextPart1492079.yORxeDNXAC Content-Type: multipart/mixed; boundary="Boundary-01=_Xrd9CIFan8zxw0w" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_Xrd9CIFan8zxw0w Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Heya folks, please find attached two patches, one against kdelibs/kioslave/file and one= =20 against kdelibs/kio, which together implement support for managing POSIX AC= Ls=20 on filesystems that support it. Please review, I'll then merge this into 3.= 5. The backend is based off of patches by Gy=F6rgy Szombathelyi and the fronte= nd=20 (kio/kfile/kacleditwidget) makes liberal use of work done by Sean Harmer in= =20 playground/base/acldlg. All bugs are mine, of course. As for the details of the patches, I guess the kioslave bits should be pret= ty=20 self-explanatory. When reading, ACLs are shipped to the user via three new= =20 atom types, while writing is done by setting two metadata strings when=20 issuing a chmod job (ACL_STRING and DEFAULT_ACL_STRING). There is a special= =20 value for deleting a previously present ACLs. The format of these strings i= s=20 that of the POSIX ACL string representation, as defined in POSIX draft=20 1003.1e/1003.2c. To encapsulate all of the acl string parsing and manipulation, and to local= ize=20 the libacl and sys/acl.h includes I've done a KACL class, which offers a ni= ce=20 interface to ACL munging and all kinds of convenience. User code (such as t= he=20 stuff in kio/kfile only needs kacl.h. KACLs can easily be created from the= =20 abovementioned POSIX strings. There's a full test suite for KACL and an extension of KioslaveTest for the= =20 three new atoms. There's extensions to KFileItem for setting and getting ACL and defaultACL. The frontend aims to integrate seamlessly with the existing interface. If t= he=20 underlying filesystem supports setting ACLs the group of checkboxes in the= =20 "Advanced properties" is replaced (not really replaced, the special bits=20 stay) by a listview, which allows adding, removing and editing of entries a= nd=20 inline toggling of permission bits. This widget takes much care to not allo= w=20 illegal (combinations of) entries, it automatically adds entries when the=20 underlying acl lib would add them as well (properly autocalculated mask=20 entries appear when you add the first extended entry, for example), you can= 't=20 add an entry for a user or group more than once, etc. The Advanced=20 Permissions keeps state between invocations, the main "Ok" does the actual= =20 chmod, as before. The state of the three newbie combos, as I affectionately= =20 call them, is kept in sync with the acl editing widget. Recursive applying of ACL changes to directories and all files/dirs in them= =20 works. Limitations/TODO: o it currently only works for a single file (no support for "partial" = =20 handling), that's the next thing I'd like to tackle once this is in o the users and groups are offered as comboboxes, which has scalability issues, I'm planing to offer a lineedit with completion when the number of available users/groups exceeds a certain limit o there might be BIC issues, I haven't checked carefully yet, if there are, I'll fix them, of course o the configure checks aren't done yet, I guess this needs to be a compile= =20 time option o there is a set of trivial kdebase patches to make the various konqueror views show a little "+" next to the permissions string, if there's an extended ACL on a file, I'll merge that once these patches are in Longer term plans: o extend it to samba, nfs, etc I'd be grateful for any testing and feedback that you might be able to spar= e. Cheerio, Till --Boundary-01=_Xrd9CIFan8zxw0w Content-Type: text/x-diff; charset="iso-8859-1"; name="POSIX-ACL-support-kioslave.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="POSIX-ACL-support-kioslave.diff" Index: file/file.cc =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- file/file.cc (.../KDE/3.5/kdelibs/kioslave) (revision 443749) +++ file/file.cc (.../work/posix-acl-support/kdelibs/kioslave) (revision 44= 3749) @@ -41,6 +41,11 @@ #include #endif =20 +#ifdef USE_POSIX_ACL +#include +#include +#endif + #include #include #include @@ -91,6 +96,12 @@ using namespace KIO; #define MAX_IPC_SIZE (1024*32) =20 static QString testLogFile( const char *_filename ); +#ifdef USE_POSIX_ACL +static bool isExtendedACL( acl_t p_acl ); +static void appendACLAtoms( const QCString & path, UDSEntry& entry,=20 + mode_t type, bool withACL ); +#endif + =20 extern "C" { KDE_EXPORT int kdemain(int argc, char **argv); } =20 @@ -122,12 +133,74 @@ FileProtocol::FileProtocol( const QCStri groupcache.setAutoDelete( true ); } =20 + +int FileProtocol::setACL( const char *path, mode_t perm, bool directoryDef= ault ) +{ + int ret =3D 0; +#ifdef USE_POSIX_ACL + + const QString ACLString =3D metaData( "ACL_STRING" ); + const QString defaultACLString =3D metaData( "DEFAULT_ACL_STRING" ); + // Empty strings mean leave as is + if ( !ACLString.isEmpty() ) { + acl_t acl =3D 0; + if ( ACLString =3D=3D "ACL_DELETE" ) { + // user told us to delete the extended ACL, so let's write onl= y=20 + // the minimal (UNIX permission bits) part + acl =3D acl_from_mode( perm ); + } + acl =3D acl_from_text( ACLString.latin1() ); + if ( acl_valid( acl ) =3D=3D 0 ) { // let's be safe + ret =3D=3D acl_set_file( path, ACL_TYPE_ACCESS, acl ); + ssize_t size =3D acl_size( acl ); + kdDebug(7101) << "Set ACL on: " << path << " to: " << acl_to_t= ext( acl, &size ) << endl; + } + acl_free( acl ); + if ( ret !=3D 0 ) return ret; // better stop trying right away + } + + if ( directoryDefault && !defaultACLString.isEmpty() ) { + if ( defaultACLString =3D=3D "ACL_DELETE" ) { + // user told us to delete the default ACL, do so + ret +=3D acl_delete_def_file( path ); + } else { + acl_t acl =3D acl_from_text( defaultACLString.latin1() ); + if ( acl_valid( acl ) =3D=3D 0 ) { // let's be safe + ret +=3D acl_set_file( path, ACL_TYPE_DEFAULT, acl ); + ssize_t size =3D acl_size( acl ); + kdDebug(7101) << "Set Default ACL on: " << path << " to: "= << acl_to_text( acl, &size ) << endl; + } + acl_free( acl ); + } + } +#endif + return ret; +} + void FileProtocol::chmod( const KURL& url, int permissions ) { =2D QCString _path( QFile::encodeName(url.path())); =2D if ( ::chmod( _path.data(), permissions ) =3D=3D -1 ) + QCString _path( QFile::encodeName(url.path()) ); + /* FIXME: Should be atomic */ + if ( ::chmod( _path.data(), permissions ) =3D=3D -1 ||=20 + ( setACL( _path.data(), permissions, false ) =3D=3D -1 ) || + /* if not a directory, cannot set default ACLs */ + ( setACL( _path.data(), permissions, true ) =3D=3D -1 && errno != =3D ENOTDIR ) ) { + + switch (errno) { + case EPERM: + case EACCES: + error( KIO::ERR_ACCESS_DENIED, url.path() ); + break; + case ENOTSUP: + error( KIO::ERR_UNSUPPORTED_ACTION, url.path() ); + break; + case ENOSPC: + error( KIO::ERR_DISK_FULL, url.path() ); + break; + default: error( KIO::ERR_CANNOT_CHMOD, url.path() ); =2D else + } + } else finished(); } =20 @@ -493,6 +566,10 @@ void FileProtocol::copy( const KURL &src QCString _src( QFile::encodeName(src.path())); QCString _dest( QFile::encodeName(dest.path())); KDE_struct_stat buff_src; +#ifdef USE_POSIX_ACL + acl_t acl; +#endif + if ( KDE_stat( _src.data(), &buff_src ) =3D=3D -1 ) { if ( errno =3D=3D EACCES ) error( KIO::ERR_ACCESS_DENIED, src.path() ); @@ -568,6 +645,15 @@ void FileProtocol::copy( const KURL &src #ifdef HAVE_FADVISE posix_fadvise(dest_fd,0,0,POSIX_FADV_SEQUENTIAL); #endif + +#ifdef USE_POSIX_ACL + acl =3D acl_get_fd(src_fd); + if ( acl && !isExtendedACL( acl ) ) { + kdDebug(7101) << _dest.data() << " doesn't have extended ACL" << e= ndl; + acl_free( acl ); + acl =3D NULL; + } +#endif totalSize( buff_src.st_size ); =20 KIO::filesize_t processed_size =3D 0; @@ -614,6 +700,9 @@ void FileProtocol::copy( const KURL &src error( KIO::ERR_COULD_NOT_READ, src.path()); close(src_fd); close(dest_fd); +#ifdef USE_POSIX_ACL + if (acl) acl_free(acl); +#endif return; } if (n =3D=3D 0) @@ -636,6 +725,9 @@ void FileProtocol::copy( const KURL &src kdWarning(7101) << "Couldn't write[2]. Error:" << strerror(e= rrno) << endl; error( KIO::ERR_COULD_NOT_WRITE, dest.path()); } +#ifdef USE_POSIX_ACL + if (acl) acl_free(acl); +#endif return; } processed_size +=3D n; @@ -651,19 +743,29 @@ void FileProtocol::copy( const KURL &src { kdWarning(7101) << "Error when closing file descriptor[2]:" << str= error(errno) << endl; error( KIO::ERR_COULD_NOT_WRITE, dest.path()); +#ifdef USE_POSIX_ACL + if (acl) acl_free(acl); +#endif return; } =20 // set final permissions if ( _mode !=3D -1 ) { =2D if (::chmod(_dest.data(), _mode) !=3D 0) + if ( (::chmod(_dest.data(), _mode) !=3D 0) +#ifdef USE_POSIX_ACL + || (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) !=3D= 0) +#endif + ) { // Eat the error if the filesystem apparently doesn't support chmo= d. if ( KIO::testFileSystemFlag( _dest, KIO::SupportsChmod ) ) warning( i18n( "Could not change permissions for\n%1" ).arg( d= est.path() ) ); } } +#ifdef USE_POSIX_ACL + if (acl) acl_free(acl); +#endif =20 // copy access and modification time struct utimbuf ut; @@ -812,7 +914,45 @@ void FileProtocol::del( const KURL& url, finished(); } =20 =2Dbool FileProtocol::createUDSEntry( const QString & filename, const QCStr= ing & path, UDSEntry & entry, short int details ) + +QString FileProtocol::getUserName( uid_t uid )=20 +{ + QString *temp; + temp =3D usercache.find( uid ); + if ( !temp ) { + struct passwd *user =3D getpwuid( uid ); + if ( user ) { + usercache.insert( uid, new QString(QString::fromLatin1(user->p= w_name)) ); + return QString::fromLatin1( user->pw_name ); + } + else + return QString::number( uid ); + } + else + return *temp; +} + +QString FileProtocol::getGroupName( gid_t gid )=20 +{ + QString *temp; + temp =3D groupcache.find( gid ); + if ( !temp ) { + struct group *grp =3D getgrgid( gid ); + if ( grp ) { + groupcache.insert( gid, new QString(QString::fromLatin1(grp->g= r_name)) ); + return QString::fromLatin1( grp->gr_name ); + } + else + return QString::number( gid ); + } + else + return *temp; +} + + + +bool FileProtocol::createUDSEntry( const QString & filename, const QCStrin= g & path, UDSEntry & entry,=20 + short int details, bool withACL ) { assert(entry.count() =3D=3D 0); // by contract :-) // Note: details =3D 0 (only "file or directory or symlink or doesn't = exist") isn't implemented @@ -883,42 +1023,24 @@ bool FileProtocol::createUDSEntry( const atom.m_long =3D buff.st_size; entry.append( atom ); =20 +#ifdef USE_POSIX_ACL + /* Append an atom indicating whether the file has extended acl informa= tion + * and if withACL is specified also one with the acl itself. If it's a= directory + * and it has a default ACL, also append that. */ + appendACLAtoms( path, entry, type, withACL ); +#endif + notype: atom.m_uds =3D KIO::UDS_MODIFICATION_TIME; atom.m_long =3D buff.st_mtime; entry.append( atom ); =20 atom.m_uds =3D KIO::UDS_USER; =2D uid_t uid =3D buff.st_uid; =2D QString *temp =3D usercache.find( uid ); =2D =2D if ( !temp ) { =2D struct passwd *user =3D getpwuid( uid ); =2D if ( user ) { =2D usercache.insert( uid, new QString(QString::fromLatin1(user-= >pw_name)) ); =2D atom.m_str =3D user->pw_name; =2D } =2D else =2D atom.m_str =3D QString::number( uid ); =2D } =2D else =2D atom.m_str =3D *temp; + atom.m_str =3D getUserName( buff.st_uid ); entry.append( atom ); =20 atom.m_uds =3D KIO::UDS_GROUP; =2D gid_t gid =3D buff.st_gid; =2D temp =3D groupcache.find( gid ); =2D if ( !temp ) { =2D struct group *grp =3D getgrgid( gid ); =2D if ( grp ) { =2D groupcache.insert( gid, new QString(QString::fromLatin1(grp-= >gr_name)) ); =2D atom.m_str =3D grp->gr_name; =2D } =2D else =2D atom.m_str =3D QString::number( gid ); =2D } =2D else =2D atom.m_str =3D *temp; + atom.m_str =3D getGroupName( buff.st_gid ); entry.append( atom ); =20 atom.m_uds =3D KIO::UDS_ACCESS_TIME; @@ -957,11 +1079,12 @@ void FileProtocol::stat( const KURL & ur kdDebug(7101) << "FileProtocol::stat details=3D" << details << endl; =20 UDSEntry entry; =2D if ( !createUDSEntry( url.fileName(), _path, entry, details ) ) + if ( !createUDSEntry( url.fileName(), _path, entry, details, true /*wi= th acls*/ ) ) { error( KIO::ERR_DOES_NOT_EXIST, url.path(-1) ); return; } + #if 0 ///////// debug code KIO::UDSEntry::ConstIterator it =3D entry.begin(); @@ -992,8 +1115,15 @@ void FileProtocol::stat( const KURL & ur case KIO::UDS_LINK_DEST: kdDebug(7101) << "LinkDest : " << ((*it).m_str.ascii() ) <= < endl; break; + case KIO::UDS_EXTENDED_ACL: + kdDebug(7101) << "Contains extended ACL " << endl; + break; } } + MetaData::iterator it1 =3D mOutgoingMetaData.begin(); + for ( ; it1 !=3D mOutgoingMetaData.end(); it1++ ) { + kdDebug(7101) << it1.key() << " =3D " << it1.data() << endl; + } ///////// #endif statEntry( entry ); @@ -1078,7 +1208,9 @@ void FileProtocol::listDir( const KURL&=20 QStrListIterator it(entryNames); for (; it.current(); ++it) { entry.clear(); =2D if ( createUDSEntry( QFile::decodeName(*it), *it /* we can use t= he filename as relative path*/, entry, 2 ) ) + if ( createUDSEntry( QFile::decodeName(*it),=20 + *it /* we can use the filename as relative pa= th*/,=20 + entry, 2, true ) ) listEntry( entry, false); else ;//Well, this should never happen... but with wrong encoding nam= es @@ -1550,4 +1682,67 @@ static QString testLogFile( const char * return result; } =20 + +/************************************* + * + * ACL handling helpers + * + *************************************/ +#ifdef USE_POSIX_ACL + +static bool isExtendedACL( acl_t acl ) +{ + return ( acl_equiv_mode( acl, 0 ) !=3D 0 ); +} + +static void appendACLAtoms( const QCString & path, UDSEntry& entry, mode_t= type, bool withACL ) +{ + // first check for a noop + if ( acl_extended_file( path.data() ) =3D=3D 0 ) return; + + acl_t acl =3D 0; + acl_t defaultAcl =3D 0; + UDSAtom atom; + bool isDir =3D S_ISDIR( type ); + // do we have an acl for the file, and/or a default acl for the dir, i= f it is one? + acl =3D acl_get_file( path.data(), ACL_TYPE_ACCESS ); + /* Sadly libacl does not provided a means of checking for extended ACL= and default + * ACL separately. Since a directory can have both, we need to check a= gain. */ + if ( isDir ) { + if ( acl ) {=20 + if ( !isExtendedACL( acl ) ) { + acl_free( acl );=20 + acl =3D 0; + } + } + defaultAcl =3D acl_get_file( path.data(), ACL_TYPE_DEFAULT ); + } + if ( acl || defaultAcl ) { + kdDebug(7101) << path.data() << " has extended ACL entries " << endl; + atom.m_uds =3D KIO::UDS_EXTENDED_ACL; + atom.m_long =3D 1; + entry.append( atom ); + } + if ( withACL ) { + if ( acl ) { + ssize_t size =3D acl_size( acl ); + atom.m_uds =3D KIO::UDS_ACL_STRING; + atom.m_str =3D QString::fromLatin1( acl_to_text( acl, &size ) = ); + entry.append( atom ); + kdDebug(7101) << path.data() << "ACL: " << atom.m_str << endl; + } + if ( defaultAcl ) { + ssize_t size =3D acl_size( defaultAcl ); + atom.m_uds =3D KIO::UDS_DEFAULT_ACL_STRING; + atom.m_str =3D QString::fromLatin1( acl_to_text( defaultAcl, &= size ) ); + entry.append( atom ); + kdDebug(7101) << path.data() << "DEFAULT ACL: " << atom.m_str = << endl; + } + } + if ( acl ) acl_free( acl ); + if ( defaultAcl ) acl_free( defaultAcl ); +} +#endif + + #include "file.moc" Index: file/file.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- file/file.h (.../KDE/3.5/kdelibs/kioslave) (revision 443749) +++ file/file.h (.../work/posix-acl-support/kdelibs/kioslave) (revision 443= 749) @@ -81,7 +81,12 @@ protected slots: =20 protected: =20 =2D bool createUDSEntry( const QString & filename, const QCString & path, = KIO::UDSEntry & entry, short int details ); + bool createUDSEntry( const QString & filename, const QCString & path, KI= O::UDSEntry & entry,=20 + short int details, bool withACL ); + int setACL( const char *path, mode_t perm, bool _directoryDefault ); + =20 + QString getUserName( uid_t uid ); + QString getGroupName( gid_t gid ); =20 QIntDict usercache; // maps long =3D=3D> QString * QIntDict groupcache; Index: file/Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- file/Makefile.am (.../KDE/3.5/kdelibs/kioslave) (revision 443749) +++ file/Makefile.am (.../work/posix-acl-support/kdelibs/kioslave) (revisio= n 443749) @@ -9,7 +9,7 @@ INCLUDES =3D $(all_includes) kde_module_LTLIBRARIES =3D kio_file.la =20 kio_file_la_SOURCES =3D file.cc =2Dkio_file_la_LIBADD =3D $(LIB_KIO) +kio_file_la_LIBADD =3D $(LIB_KIO) $(ACL_LIBS) kio_file_la_LDFLAGS =3D $(all_libraries) -module $(KDE_PLUGIN)=20 noinst_HEADERS =3D file.h =20 --Boundary-01=_Xrd9CIFan8zxw0w Content-Type: text/x-diff; charset="iso-8859-1"; name="POSIX-ACL-support-kio.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="POSIX-ACL-support-kio.diff" Index: kio/kfileitem.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/kfileitem.cpp (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kio/kfileitem.cpp (.../work/posix-acl-support/kdelibs/kio) (revision 44= 3749) @@ -45,6 +45,7 @@ #include #include #include +#include =20 class KFileItem::KFileItemPrivate { public: @@ -344,6 +345,39 @@ KIO::filesize_t KFileItem::size() const return 0L; } =20 +bool KFileItem::hasExtendedACL() const +{ + KIO::UDSEntry::ConstIterator it =3D m_entry.begin(); + for( ; it !=3D m_entry.end(); it++ ) + if ( (*it).m_uds =3D=3D KIO::UDS_EXTENDED_ACL ) { + return true; + } + return false; +} + +KACL KFileItem::ACL() const +{ + if ( hasExtendedACL() ) { + // Extract it from the KIO::UDSEntry + KIO::UDSEntry::ConstIterator it =3D m_entry.begin(); + for( ; it !=3D m_entry.end(); ++it ) + if ( (*it).m_uds =3D=3D KIO::UDS_ACL_STRING ) + return KACL((*it).m_str); + } + // create one from the basic permissions + return KACL( m_permissions ); +} + +KACL KFileItem::defaultACL() const +{ + // Extract it from the KIO::UDSEntry + KIO::UDSEntry::ConstIterator it =3D m_entry.begin(); + for( ; it !=3D m_entry.end(); ++it ) + if ( (*it).m_uds =3D=3D KIO::UDS_DEFAULT_ACL_STRING ) + return KACL((*it).m_str); + return KACL(); +} + time_t KFileItem::time( unsigned int which ) const { unsigned int mappedWhich =3D 0; @@ -890,7 +924,7 @@ QString KFileItem::permissionsString() c =20 QString KFileItem::parsePermissions(mode_t perm) const { =2D char p[] =3D "----------"; + char p[] =3D "---------- "; =20 if (isDir()) p[0]=3D'd'; @@ -901,22 +935,28 @@ QString KFileItem::parsePermissions(mode p[1]=3D'r'; if (perm & QFileInfo::WriteUser) p[2]=3D'w'; =2D if (perm & QFileInfo::ExeUser) =2D p[3]=3D'x'; + if ((perm & QFileInfo::ExeUser) && !(perm & S_ISUID)) p[3]=3D'x'; + else if ((perm & QFileInfo::ExeUser) && (perm & S_ISUID)) p[3]=3D's'; + else if (!(perm & QFileInfo::ExeUser) && (perm & S_ISUID)) p[3]=3D'S'; =20 if (perm & QFileInfo::ReadGroup) p[4]=3D'r'; if (perm & QFileInfo::WriteGroup) p[5]=3D'w'; =2D if (perm & QFileInfo::ExeGroup) =2D p[6]=3D'x'; + if ((perm & QFileInfo::ExeGroup) && !(perm & S_ISGID)) p[6]=3D'x'; + else if ((perm & QFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]=3D's'; + else if (!(perm & QFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]=3D'S'; =20 if (perm & QFileInfo::ReadOther) p[7]=3D'r'; if (perm & QFileInfo::WriteOther) p[8]=3D'w'; =2D if (perm & QFileInfo::ExeOther) =2D p[9]=3D'x'; + if ((perm & QFileInfo::ExeOther) && !(perm & S_ISVTX)) p[9]=3D'x'; + else if ((perm & QFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]=3D't'; + else if (!(perm & QFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]=3D'T'; + + if (hasExtendedACL()) + p[10]=3D'+'; =20 return QString::fromLatin1(p); } Index: kio/kacl.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/kacl.cpp (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kio/kacl.cpp (.../work/posix-acl-support/kdelibs/kio) (revision 443749) @@ -0,0 +1,524 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Till Adam + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public Licen= se + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// $Id: kacl.cpp 424977 2005-06-13 15:13:22Z tilladam $ + +#include +#include +#include +#include +#include +#include + +#include + +#include "kacl.h" + +class KACL::KACLPrivate { + public: + bool dummy; +}; + +KACL::KACL( const QString &aclString )=20 + : m_acl( 0 ), + d(0) +{ + setACL( aclString ); + init(); +} + +KACL::KACL( mode_t basePermissions )=20 + : m_acl( acl_from_mode( basePermissions ) ), + d(0) +{ + init(); +} + +KACL::KACL() + : m_acl( 0 ), + d(0) +{ +} + +KACL::KACL( const KACL& rhs ) + : m_acl( 0 ), + d(0) +{ + setACL( rhs.asString() ); +} + +void KACL::init() +{ + m_usercache.setAutoDelete( true ); + m_groupcache.setAutoDelete( true ); +} + +KACL::~KACL() +{ + if ( m_acl ) acl_free( m_acl ); +} + +bool KACL::isValid() const +{ + bool valid =3D false; + if ( m_acl ) { + valid =3D ( acl_valid( m_acl ) =3D=3D 0 ); + } + return valid; +} + +bool KACL::isExtended() const +{ + return ( acl_equiv_mode( m_acl, NULL ) !=3D 0 ); +} + +static acl_entry_t entryForTag( acl_t acl, acl_tag_t tag ) +{ + acl_entry_t entry; + int ret =3D acl_get_entry( acl, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D tag ) + return entry; + ret =3D acl_get_entry( acl, ACL_NEXT_ENTRY, &entry ); + } + return 0; +} + +static unsigned short entryToPermissions( acl_entry_t entry ) +{ + if ( entry =3D=3D 0 ) return 0; + acl_permset_t permset; + if ( acl_get_permset( entry, &permset ) !=3D 0 ) return 0; + return( acl_get_perm( permset, ACL_READ ) << 2 | + acl_get_perm( permset, ACL_WRITE ) << 1 | + acl_get_perm( permset, ACL_EXECUTE ) ); +} + +static void permissionsToEntry( acl_entry_t entry, unsigned short v ) +{ + if ( entry =3D=3D 0 ) return; + acl_permset_t permset; + if ( acl_get_permset( entry, &permset ) !=3D 0 ) return; + acl_clear_perms( permset ); + if ( v & 4 ) acl_add_perm( permset, ACL_READ ); + if ( v & 2 ) acl_add_perm( permset, ACL_WRITE ); + if ( v & 1 ) acl_add_perm( permset, ACL_EXECUTE ); +} + +static void printACL( acl_t acl, const QString &comment ) +{ + ssize_t size =3D acl_size( acl ); + kdDebug() << comment << acl_to_text( acl, &size ) << endl; +} + +static int getUidForName( const QString& name ) +{ + struct passwd *user =3D getpwnam( name.latin1() ); + if ( user ) + return user->pw_uid; + else + return -1; +} + +static int getGidForName( const QString& name ) +{ + struct group *group =3D getgrnam( name.latin1() ); + if ( group ) + return group->gr_gid; + else + return -1; +} + +// ------------------ begin API implementation ------------ + +unsigned short KACL::ownerPermissions() const +{ + return entryToPermissions( entryForTag( m_acl, ACL_USER_OBJ ) ); +} + +bool KACL::setOwnerPermissions( unsigned short v ) +{ + permissionsToEntry( entryForTag( m_acl, ACL_USER_OBJ ), v ); + return true; +} + +unsigned short KACL::owningGroupPermissions() const +{ + return entryToPermissions( entryForTag( m_acl, ACL_GROUP_OBJ ) ); +} + +bool KACL::setOwningGroupPermissions( unsigned short v ) +{ + permissionsToEntry( entryForTag( m_acl, ACL_GROUP_OBJ ), v ); + return true; +} + +unsigned short KACL::othersPermissions() const +{ + return entryToPermissions( entryForTag( m_acl, ACL_OTHER ) ); +} + +bool KACL::setOthersPermissions( unsigned short v ) +{ + permissionsToEntry( entryForTag( m_acl, ACL_OTHER ), v ); + return true; +} + +mode_t KACL::basePermissions() const +{ + mode_t perms( 0 ); + if ( ownerPermissions() & ACL_READ ) perms |=3D S_IRUSR; + if ( ownerPermissions() & ACL_WRITE ) perms |=3D S_IWUSR; + if ( ownerPermissions() & ACL_EXECUTE ) perms |=3D S_IXUSR; + if ( owningGroupPermissions() & ACL_READ ) perms |=3D S_IRGRP; + if ( owningGroupPermissions() & ACL_WRITE ) perms |=3D S_IWGRP; + if ( owningGroupPermissions() & ACL_EXECUTE ) perms |=3D S_IXGRP; + if ( othersPermissions() & ACL_READ ) perms |=3D S_IROTH; + if ( othersPermissions() & ACL_WRITE ) perms |=3D S_IWOTH; + if ( othersPermissions() & ACL_EXECUTE ) perms |=3D S_IXOTH; + + return perms; +} + +unsigned short KACL::maskPermissions( bool &exists ) const +{ + exists =3D true; + acl_entry_t entry =3D entryForTag( m_acl, ACL_MASK ); + if ( entry =3D=3D 0 ) { + exists =3D false; + return 0; + } + return entryToPermissions( entry ); +} + +bool KACL::setMaskPermissions( unsigned short v ) +{ + permissionsToEntry( entryForTag( m_acl, ACL_MASK ), v ); + return true; +} + + +/************************** + * Deal with named users * + **************************/ +unsigned short KACL::namedUserPermissions( const QString& name, bool *exis= ts ) const +{ + acl_entry_t entry; + uid_t id; + *exists =3D false; + int ret =3D acl_get_entry( m_acl, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D ACL_USER ) { + id =3D *( (uid_t*) acl_get_qualifier( entry ) ); + if ( getUserName( id ) =3D=3D name ) { + *exists =3D true; + return entryToPermissions( entry ); + } + } + ret =3D acl_get_entry( m_acl, ACL_NEXT_ENTRY, &entry ); + } + return 0; +} + +bool KACL::setNamedUserOrGroupPermissions( const QString& name, unsigned s= hort permissions, acl_tag_t type ) +{ + acl_t newACL =3D acl_dup( m_acl ); + acl_entry_t entry; + bool allIsWell =3D true; + bool createdNewEntry =3D false; + bool found =3D false; + int ret =3D acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D type ) { + int id =3D * (int*)acl_get_qualifier( entry ); + const QString entryName =3D type =3D=3D ACL_USER? getUserName(= id ): getGroupName( id ); + if ( entryName =3D=3D name ) { + // found him, update + permissionsToEntry( entry, permissions ); + found =3D true; + break; + } + } + ret =3D acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry ); + } + if ( !found ) { + acl_create_entry( &newACL, &entry ); + acl_set_tag_type( entry, type ); + int id =3D type =3D=3D ACL_USER? getUidForName( name ): getGidForN= ame( name ); + if ( id =3D=3D -1 || acl_set_qualifier( entry, &id ) !=3D 0 ) { + acl_delete_entry( newACL, entry ); + allIsWell =3D false; + } else { + permissionsToEntry( entry, permissions ); + createdNewEntry =3D true; + } + } + if ( allIsWell && createdNewEntry ) { + // 23.1.1 of 1003.1e states that as soon as there is a named user = or + // named group entry, there needs to be a mask entry as well, so a= dd=20 + // one. + setMaskPermissions( acl_calc_mask( &newACL ) ); + } + + if ( !allIsWell || acl_valid( newACL ) !=3D 0 ) { + acl_free( newACL ); + allIsWell =3D false; + } else { + acl_free( m_acl ); + m_acl =3D newACL; + } + return allIsWell; +} + +bool KACL::setNamedUserPermissions( const QString& name, unsigned short pe= rmissions ) +{ + return setNamedUserOrGroupPermissions( name, permissions, ACL_USER ); +} + +ACLUserPermissionsList KACL::allUserPermissions() const +{ + ACLUserPermissionsList list; + acl_entry_t entry; + uid_t id; + int ret =3D acl_get_entry( m_acl, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D ACL_USER ) { + id =3D *( (uid_t*) acl_get_qualifier( entry ) ); + QString name =3D getUserName( id ); + unsigned short permissions =3D entryToPermissions( entry ); + ACLUserPermissions pair =3D qMakePair( name, permissions ); + list.append( pair ); + } + ret =3D acl_get_entry( m_acl, ACL_NEXT_ENTRY, &entry ); + } + return list; +} + +bool KACL::setAllUsersOrGroups( const QValueList< QPair > &list, acl_tag_t type ) +{ + bool allIsWell =3D true;=20 + bool atLeastOneUserOrGroup =3D false; + + // make working copy, in case something goes wrong + acl_t newACL =3D acl_dup( m_acl );=20 + acl_entry_t entry; + +//printACL( newACL, "Before cleaning: " ); + // clear user entries + int ret =3D acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D type ) { + acl_delete_entry( newACL, entry ); + // we have to start from the beginning, the iterator is=20 + // invalidated, on deletion + ret =3D acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); + } else { + ret =3D acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry ); + } + } +//printACL( newACL, "After cleaning out entries: " ); + + // now add the entries from the list + QValueList< QPair >::const_iterator it =3D li= st.constBegin(); + while ( it !=3D list.constEnd() ) { + acl_create_entry( &newACL, &entry ); + acl_set_tag_type( entry, type ); + int id =3D type =3D=3D ACL_USER? getUidForName( (*it).first):getGi= dForName( (*it).first ); + if ( id =3D=3D -1 || acl_set_qualifier( entry, &id ) !=3D 0 ) { + // user or group doesn't exist =3D> error + acl_delete_entry( newACL, entry ); + allIsWell =3D false; + break; + } else { + permissionsToEntry( entry, (*it).second ); + atLeastOneUserOrGroup =3D true; + } + ++it; + } +//printACL( newACL, "After adding entries: " ); + if ( allIsWell && atLeastOneUserOrGroup ) { + // 23.1.1 of 1003.1e states that as soon as there is a named user = or + // named group entry, there needs to be a mask entry as well, so a= dd=20 + // one. + setMaskPermissions( acl_calc_mask( &newACL ) ); + } + if ( allIsWell && ( acl_valid( newACL ) =3D=3D 0 ) ) { + acl_free( m_acl ); + m_acl =3D newACL; + } else { + acl_free( newACL ); + } + return allIsWell; +} + +bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users ) +{ + return setAllUsersOrGroups( users, ACL_USER ); +} + + +/************************** + * Deal with named groups * + **************************/ + +unsigned short KACL::namedGroupPermissions( const QString& name, bool *exi= sts ) const +{ + *exists =3D false; + acl_entry_t entry; + gid_t id; + int ret =3D acl_get_entry( m_acl, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D ACL_GROUP ) { + id =3D *( (gid_t*) acl_get_qualifier( entry ) ); + if ( getGroupName( id ) =3D=3D name ) { + *exists =3D true; + return entryToPermissions( entry ); + } + } + ret =3D acl_get_entry( m_acl, ACL_NEXT_ENTRY, &entry ); + } + + return 0; +} + +bool KACL::setNamedGroupPermissions( const QString& name, unsigned short p= ermissions ) +{ + return setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP ); +} + + +ACLGroupPermissionsList KACL::allGroupPermissions() const +{ + ACLGroupPermissionsList list; + acl_entry_t entry; + gid_t id; + int ret =3D acl_get_entry( m_acl, ACL_FIRST_ENTRY, &entry ); + while ( ret =3D=3D 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag =3D=3D ACL_GROUP ) { + id =3D *( (gid_t*) acl_get_qualifier( entry ) ); + QString name =3D getGroupName( id );=20 + unsigned short permissions =3D entryToPermissions( entry ); + ACLGroupPermissions pair =3D qMakePair( name, permissions ); + list.append( pair ); + } + ret =3D acl_get_entry( m_acl, ACL_NEXT_ENTRY, &entry ); + } + return list; +} + +bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups ) +{ + return setAllUsersOrGroups( groups, ACL_GROUP ); +} + +/************************** + * from and to string * + **************************/ + +bool KACL::setACL( const QString &aclStr ) +{ + bool ret =3D false; + acl_t temp =3D acl_from_text( aclStr.latin1() ); + if ( acl_valid( temp ) !=3D 0 ) { + // TODO errno is set, what to do with it here? + acl_free( temp ); + } else { + if ( m_acl ) + acl_free( m_acl ); + m_acl =3D temp; + ret =3D true; + } + return ret; +} + +QString KACL::asString() const +{ + ssize_t size =3D acl_size( m_acl ); + return QString::fromLatin1( acl_to_text( m_acl, &size ) ); +} + + +// helpers + +QString KACL::getUserName( uid_t uid ) const +{ + QString *temp; + temp =3D m_usercache.find( uid ); + if ( !temp ) { + struct passwd *user =3D getpwuid( uid ); + if ( user ) { + m_usercache.insert( uid, new QString(QString::fromLatin1(user-= >pw_name)) ); + return QString::fromLatin1( user->pw_name ); + } + else + return QString::number( uid ); + } + else + return *temp; +} + + +QString KACL::getGroupName( gid_t gid ) const +{ + QString *temp; + temp =3D m_groupcache.find( gid ); + if ( !temp ) { + struct group *grp =3D getgrgid( gid ); + if ( grp ) { + m_groupcache.insert( gid, new QString(QString::fromLatin1(grp-= >gr_name)) ); + return QString::fromLatin1( grp->gr_name ); + } + else + return QString::number( gid ); + } + else + return *temp; +} + +void KACL::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +QDataStream & operator<< ( QDataStream & s, const KACL & a ) +{ + s << a.asString(); + return s; +} + +QDataStream & operator>> ( QDataStream & s, KACL & a ) +{ + QString str; + s >> str; + a.setACL( str ); + return s; +} + +// vim:set ts=3D8 sw=3D4: Index: kio/kacl.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/kacl.h (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kio/kacl.h (.../work/posix-acl-support/kdelibs/kio) (revision 443749) @@ -0,0 +1,221 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Till Adam + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public Licen= se + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __kacl_h__ +#define __kacl_h__ + +#include +#include + +#include + +#include + + +typedef QPair ACLUserPermissions; +typedef QValueList ACLUserPermissionsList; +typedef QValueListIterator ACLUserPermissionsIterator; +typedef QValueListConstIterator ACLUserPermissionsCons= tIterator; + +typedef QPair ACLGroupPermissions; +typedef QValueList ACLGroupPermissionsList; +typedef QValueListIterator ACLGroupPermissionsIterato= r; +typedef QValueListConstIterator ACLGroupPermissionsCo= nstIterator; + +/** + * The KCAL class encapsulates a POSIX Access Control List. It follows the= =20 + * little standard that couldn't, 1003.1e/1003.2c, which died in draft sta= tus. + * @short a POSIX ACL encapsulation + * @author Till Adam + */ +class KIO_EXPORT KACL +{ +public: + /** + * Creates a new KACL from @p aclString. If the string is a valid acl + * string, isValid() will afterwards return true. + */ + KACL( const QString & aclString ); + + /** Copy ctor */ + KACL( const KACL& rhs ); + + /**=20 + * Creates a new KACL from the basic permissions passed in @p basicPermi= ssions. + * isValid() will return true, afterwards. + */ + KACL( mode_t basicPermissions ); + + /** + * Creates an empty KACL. Until a valid acl string is set via setACL, + * isValid() will return false. + */ + KACL(); + + virtual ~KACL(); + + KACL& operator=3D( const KACL& rhs ) {=20 + if ( this !=3D &rhs ) + setACL( rhs.asString() ); + return *this; + } + + bool operator=3D=3D( const KACL& rhs ) const { + return ( acl_cmp( m_acl, rhs.m_acl ) =3D=3D 0 ); + } + + bool operator!=3D( const KACL& rhs ) const { + return !operator=3D=3D( rhs ); + } + + /** + * Returns whether the KACL object represents a valid acl. + * @return whether the KACL object represents a valid acl. + */ + bool isValid() const; + + /** The standard (non-extended) part of an ACL. These map directly to=20 + * standard unix file permissions. Setting them will never make a valid + * ACL invalid. */ + + /** @return the owner's premissions entry */ + unsigned short ownerPermissions() const; + + /** Set the owner's permissions entry. + * @return success or failure */ + bool setOwnerPermissions( unsigned short ); + + /** @return the owning group's premissions entry */ + unsigned short owningGroupPermissions() const; + + /** Set the owning group's permissions entry. + * @return success or failure */ + bool setOwningGroupPermissions( unsigned short ); + + /** @return the premissions entry for others */ + unsigned short othersPermissions() const; + + /** Set the permissions entry for others. + * @return success or failure */ + bool setOthersPermissions( unsigned short ); + + /** @return the basic (owner/group/others) part of the ACL as a mode_t */ + mode_t basePermissions() const; + + /** The interface to the extended ACL. This is a mask, permissions for=20 + * n named users and permissions for m named groups. */ + + /** + * Return whether the ACL contains extended entries or can be expressed + * using only basic file permissions. + * @return whether the ACL contains extended entries */ + bool isExtended() const; + + /** + * Return the entry for the permissions mask if there is one and sets + * @param exists to true. If there is no such entry, @param is set to fa= lse. + * @return the permissions mask entry */ + unsigned short maskPermissions( bool &exists ) const; + + /** Set the permissions mask for the ACL. Permissions set for individual= =20 + * entries will be masked with this, such that their effective permissio= ns + * are the result of the logical and of their entry and the mask.=20 + * @return success or failure */ + bool setMaskPermissions( unsigned short ); + + /**=20 + * Access to the permissions entry for a named user, if such an entry=20 + * exists. @param exists is set to true if a matching entry exists and + * to false otherwise. + * @return the permissions for a user entry with the name in @p name */ + unsigned short namedUserPermissions( const QString& name, bool *exits ) = const; + /** Set the permissions for a user with the name @p name. Will fail + * if the user doesn't exist, in which case the ACL will be unchanged. + * @return success or failure. */ + bool setNamedUserPermissions( const QString& name, unsigned short ); + + /** Returns the list of all group permission entries. Each entry consists + * of a name/permissions pair. This is a QPair, therefor access is provi= ded=20 + * via the .first and .next members. + * @return the list of all group permission entries. */ + ACLUserPermissionsList KACL::allUserPermissions() const; + + /** Replace the list of all user permissions with @p list. If one + * of the entries in the list does not exists, or setting of the ACL + * entry fails for any reason, the ACL will be left unchanged. + * @return success or failure */ + bool setAllUserPermissions( const ACLUserPermissionsList &list ); + + /** + * Access to the permissions entry for a named group, if such an entry=20 + * exists. @param exists is set to true if a matching entry exists and + * to false otherwise. + * @return the permissions for a group with the name in @p name */ + unsigned short namedGroupPermissions( const QString& name, bool *exists = ) const; + + /** Set the permissions for a group with the name @p name. Will fail + * if the group doesn't exist, in which case the ACL be unchanged. + * @return success or failure. */ + bool setNamedGroupPermissions( const QString& name, unsigned short ); + + /** Returns the list of all group permission entries. Each entry consists + * of a name/permissions pair. This is a QPair, therefor access is provi= ded=20 + * via the .first and .next members. + * @return the list of all group permission entries. */ + + ACLGroupPermissionsList KACL::allGroupPermissions() const; + /** Replace the list of all user permissions with @p list. If one + * of the entries in the list does not exists, or setting of the ACL + * entry fails for any reason, the ACL will be left unchanged. + * @return success or failure */ + bool setAllGroupPermissions( const ACLGroupPermissionsList & ); + + /** Sets the whole list from a string. If the string in @p aclStr repres= ents=20 + * a valid ACL, it will be set, otherwise the ACL remains unchanged. + * @return whether setting the ACL was successful. */ + bool setACL( const QString &aclStr ); + + /** Return a string representation of the ACL. + * @return a string version of the ACL in the format compatible with lib= acl and + * POSIX 1003.1e. Implementations conforming to that standard should be = able + * to take such strings as input. */ + QString asString() const; + +protected: + // helpers + QString getUserName( uid_t uid ) const; + QString getGroupName( gid_t gid ) const; + bool setAllUsersOrGroups( const QValueList< QPair > &list, acl_tag_t type ); + bool setNamedUserOrGroupPermissions( const QString& name, unsigned short= permissions, acl_tag_t type ); + virtual void virtual_hook( int id, void* data ); +private: + void init(); + acl_t m_acl; + mutable QIntDict m_usercache; + mutable QIntDict m_groupcache; + class KACLPrivate; + KACLPrivate * d; + KIO_EXPORT friend QDataStream & operator<< ( QDataStream & s, const KACL= & a ); + KIO_EXPORT friend QDataStream & operator>> ( QDataStream & s, KACL & a ); +}; + +KIO_EXPORT QDataStream & operator<< ( QDataStream & s, const KACL & a ); +KIO_EXPORT QDataStream & operator>> ( QDataStream & s, KACL & a ); + +#endif Index: kio/Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/Makefile.am (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kio/Makefile.am (.../work/posix-acl-support/kdelibs/kio) (revision 4437= 49) @@ -42,6 +42,9 @@ libksycoca_la_SOURCES =3D \ kdatatool.cpp karchive.cpp kfilefilter.cpp \ kfilemetainfo.cpp kdcopservicestarter.cpp \ dataslave.cpp dataprotocol.cpp +#if USE_POSIX_ACL + libksycoca_la_SOURCES +=3D kacl.cpp +#endif =20 include_HEADERS =3D \ kservicetype.h kmimetype.h kmimemagic.h kservice.h \ @@ -55,6 +58,10 @@ include_HEADERS =3D \ karchive.h kfilefilter.h kfilemetainfo.h renamedlgplugin.h \ kmimetyperesolver.h kdcopservicestarter.h kremoteencoding.h \ kmimetypechooser.h +#if USE_POSIX_ACL +include_HEADERS +=3D kacl.h +#endif + =20 #libkiocore_la_LDFLAGS =3D $(all_libraries) #libkiocore_la_LIBADD =3D ../../kdeui/libkdeui.la ../../kdesu/libkdesu.la = $(LIBZ) $(LIBFAM) $(LIBVOLMGT) @@ -98,6 +105,8 @@ kioinclude_HEADERS =3D connection.h \ ioslave_defaults.h http_slave_defaults.h previewjob.h thumbcreator.h \ metainfojob.h davjob.h renamedlg.h skipdlg.h =20 + + =20 # Internal noinst_HEADERS =3D kservicetypefactory.h kservicefactory.h \ kmessageboxwrapper.h \ Index: kio/kfileitem.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/kfileitem.h (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kio/kfileitem.h (.../work/posix-acl-support/kdelibs/kio) (revision 4437= 49) @@ -26,6 +26,7 @@ #include #include #include +#include #include #include =20 @@ -139,6 +140,27 @@ public: QString permissionsString() const; =20 /** + * Tells if the file has extended access level information ( Posix ACL ) + * @return true if the file has extend ACL information or false if it ha= sn't + * @since 3.5 + */ + bool hasExtendedACL() const; + + /** + * Returns the access control list for the file. + * @return the access control list as a KACL + * @since 3.5 + */ + KACL ACL() const; + + /** + * Returns the default access control list for the directory. + * @return the default access control list as a KACL + * @since 3.5 + */ + KACL defaultACL() const; + + /** * Returns the file type (stat.st_mode containing only S_IFDIR, S_IFLNK,= ...). * @return the file type */ Index: kio/global.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/global.h (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kio/global.h (.../work/posix-acl-support/kdelibs/kio) (revision 443749) @@ -325,8 +325,19 @@ namespace KIO /// A local file path if the ioslave display files sitting /// on the local filesystem (but in another hierarchy, e.g. media:/) UDS_LOCAL_PATH =3D 72 | UDS_STRING, + /// Indicates that the entry has extended ACL entries + /// @since 3.5 + UDS_EXTENDED_ACL =3D 80 | UDS_LONG, + /// The access control list serialized into a single string. + /// @since 3.5 + UDS_ACL_STRING =3D 88 | UDS_STRING, + + /// The default access control list serialized into a single string. + /// Only available for directories. + /// @since 3.5 + UDS_DEFAULT_ACL_STRING =3D 96 | UDS_STRING, =20 =2D // available: 80, 88, 92, 100, 108 etc. + // available: 104, 112, 120=20 =20 /// Access permissions (part of the mode returned by stat) UDS_ACCESS =3D 128 | UDS_LONG, @@ -352,7 +363,7 @@ namespace KIO UDS_GUESSED_MIME_TYPE =3D 16392 | UDS_STRING, /// XML properties, e.g. for WebDAV /// @since 3.1 =2D UDS_XML_PROPERTIES =3D 32768 | UDS_STRING + UDS_XML_PROPERTIES =3D 0x8000 | UDS_STRING }; =20 /** Index: kio/chmodjob.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kio/chmodjob.cpp (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kio/chmodjob.cpp (.../work/posix-acl-support/kdelibs/kio) (revision 443= 749) @@ -183,6 +183,13 @@ void ChmodJob::chmodNextFile() kdDebug(7007) << "ChmodJob::chmodNextFile chmod'ing " << info.url.= prettyURL() << " to " << QString::number(info.permissions,8) << = endl; KIO::SimpleJob * job =3D KIO::chmod( info.url, info.permissions ); + // copy the metadata for acl and default acl + const QString aclString =3D queryMetaData( "ACL_STRING" ); + const QString defaultAclString =3D queryMetaData( "DEFAULT_ACL_STR= ING" ); + if ( !aclString.isEmpty() ) + job->addMetaData( "ACL_STRING", aclString ); + if ( !defaultAclString.isEmpty() ) + job->addMetaData( "DEFAULT_ACL_STRING", defaultAclString ); addSubjob(job); } else Index: kfile/kacleditwidget.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/kacleditwidget.h (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kfile/kacleditwidget.h (.../work/posix-acl-support/kdelibs/kio) (revisi= on 443749) @@ -0,0 +1,54 @@ +/*************************************************************************= ** + * Copyright (C) 2005 by Sean Harmer = * + * Till Adam = * + * = * + * This program is free software; you can redistribute it and/or modify = * + * it under the terms of the GNU General Public License as published by = * + * the Free Software Foundation; either version 2 of the License, or = * + * (at your option) any later version. = * + * = * + * This program is distributed in the hope that it will be useful, = * + * but WITHOUT ANY WARRANTY; without even the implied warranty of = * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the = * + * GNU General Public License for more details. = * + * = * + * You should have received a copy of the GNU General Public License = * + * along with this program; if not, write to the = * + * Free Software Foundation, Inc., = * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. = * + *************************************************************************= **/ +#ifndef KACLEDITWIDGET_H +#define KACLEDITWIDGET_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +class KACLListViewItem; +class KACLListView; +class QPushButton; + +class KACLEditWidget : QWidget +{ + Q_OBJECT +public: + KACLEditWidget( QWidget *parent =3D 0, const char *name =3D 0 ); + KACL getACL() const; + KACL getDefaultACL() const; + void setACL( const KACL & ); + void setDefaultACL( const KACL & ); +private slots: + void slotUpdateButtons(); +private: + KACLListView* m_listView; + QPushButton *m_AddBtn; + QPushButton *m_EditBtn; + QPushButton *m_DelBtn; +}; + + +#endif Index: kfile/kpropertiesdialog.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/kpropertiesdialog.h (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kfile/kpropertiesdialog.h (.../work/posix-acl-support/kdelibs/kio) (rev= ision 443749) @@ -35,6 +35,7 @@ #include #include #include +#include =20 class QLineEdit; class QCheckBox; @@ -45,6 +46,7 @@ class QButton; class KIconButton; class KPropsDlgPlugin; class QComboBox; +class QGroupBox; =20 #define KPropsPage KPropsDlgPlugin =20 Index: kfile/images.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/images.h (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kfile/images.h (.../work/posix-acl-support/kdelibs/kio) (revision 44374= 9) @@ -0,0 +1,275 @@ +#ifndef _QEMBED_1804289383 +#define _QEMBED_1804289383 +#include +#include +static const QRgb group_grey_data[] =3D { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x42484848,0xc39b9b9b,0xeab1b1b1,0xce9= d9d9d,0x5a4d4d4d,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x563b3b3b,0xfdaeaeae,0xffcfcfcf,0= xffcccccc,0xffcecece, + 0xffbababa,0x62393939,0x0,0x0,0x0,0x0,0x0,0x0,0x4525252,0x9383838,0x0,= 0xd0515151,0xff969696,0xff959595, + 0xff969696,0xff959595,0xff969696,0xdd505050,0x6000000,0x0,0x0,0x0,0xa1= 91919,0x908f8f8f,0xebc1c1c1,0xf6c6c6c6,0xc0a1a1a1,0xf74f4f4f, + 0xff626262,0xff6a6a6a,0xff6c6c6c,0xff6a6a6a,0xff636363,0xfb4a4a4a,0x1a= 000000,0x0,0x0,0x0,0xa3828282,0xffdfdfdf,0xffdedede,0xffdddddd, + 0xffe0e0e0,0xffa4a4a4,0xff636363,0xff666666,0xff6a6a6a,0xff676767,0xff= 5f5f5f,0xe6494949,0xd000000,0x0,0x0,0x21232323,0xfca2a2a2,0xffc3c3c3, + 0xffc6c6c6,0xffc6c6c6,0xffc4c4c4,0xffbababa,0xff717171,0xff7e7e7e,0xff= 7e7e7e,0xff7d7d7d,0xfe6f6f6f,0x812b2b2b,0x0,0x0,0x0,0x3e303030, + 0xffa6a6a6,0xffb7b7b7,0xffbdbdbd,0xffbebebe,0xffb9b9b9,0xffacacac,0xff= 808080,0xff8f8f8f,0xff939393,0xff909090,0xf86b6b6b,0x34202020,0x0,0x0, + 0x0,0x1c191919,0xf8a5a5a5,0xffc2c2c2,0xffcccccc,0xffcecece,0xffc5c5c5,= 0xffbababa,0xff888888,0xffa5a5a5,0xffa4a4a4,0xffa5a5a5,0xffa1a1a1,0xd351515= 1, + 0x8030303,0x0,0x0,0x0,0x8f6f6f6f,0xffd3d3d3,0xffe2e2e2,0xffe3e3e3,0xff= dbdbdb,0xff9b9b9b,0xff6f6f6f,0xff727272,0xff6e6e6e,0xff717171, + 0xff707070,0xff606060,0x62363636,0x0,0x0,0x0,0x6e5b5b5b,0xffb4b4b4,0xf= fd4d4d4,0xffdadada,0xffcecece,0xff737373,0xff656565,0xff676767, + 0xff696969,0xff676767,0xff636363,0xff5d5d5d,0xc44b4b4b,0x0,0x0,0x27343= 434,0xf5a5a5a5,0xffd1d1d1,0xffd2d2d2,0xffd1d1d1,0xffd1d1d1,0xffc3c3c3, + 0xff7b7b7b,0xff6f6f6f,0xff727272,0xff6f6f6f,0xff696969,0xff626262,0xf7= 606060,0x16050505,0x0,0xa07d7d7d,0xffb8b8b8,0xffc0c0c0,0xffc2c2c2,0xffc1c1c= 1, + 0xffc1c1c1,0xffbbbbbb,0xffa6a6a6,0xff868686,0xff858585,0xff838383,0xff= 838383,0xff878787,0xe95e5e5e,0x19050505,0xd141414,0xf0a2a2a2,0xffbdbdbd,0xf= fc6c6c6, + 0xffcbcbcb,0xffcbcbcb,0xffc8c8c8,0xffc0c0c0,0xffb8b8b8,0xef8b8b8b,0xd6= 707070,0xd26a6a6a,0xbb595959,0x82363636,0x24070707,0x0,0x44505050,0xffc0c0c= 0, + 0xffc7c7c7,0xffd2d2d2,0xffd9d9d9,0xffdadada,0xffd4d4d4,0xffcacaca,0xff= c1c1c1,0xc8979797,0x3000000,0x4000000,0x0,0x0,0x0,0x0, + 0x2b393939,0xeeaaaaaa,0xffdadada,0xffe4e4e4,0xffeaeaea,0xffeaeaea,0xff= e4e4e4,0xffdddddd,0xffd1d1d1,0xae797979,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x1e0f0f0f,0x76575757,0xae898989,0xc49c9c9c,0xc6a0a0a0,0xb= c9a9a9a,0x98808080,0x57414141,0xb000000,0x0,0x0, + 0x0,0x0,0x0,0x0 +}; + +/* Generated by qembed */ +static const QRgb group_data[] =3D { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4223731d,0xc37fbb7c,0xea9bca98,0xce8= 6b982,0x5a316e2c,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x56146610,0xfd8fce8e,0xffbae4bb,0= xffb7e2b7,0xffbae3ba, + 0xff9ed89d,0x62166112,0x0,0x0,0x0,0x0,0x0,0x0,0x4003ca5,0x9003171,0x0,= 0xd0198b17,0xff6ac468,0xff6ec665, + 0xff70c865,0xff6ec665,0xff6ac468,0xdd1a8918,0x6000000,0x0,0x0,0x0,0xa0= 01333,0x905b8cc4,0xeb9fc0e4,0xf6a8c5e4,0xc07a9dc9,0xf7108e1e, + 0xff2eb113,0xff42be17,0xff49c216,0xff44be17,0xff31b214,0xfb109301,0x1a= 000000,0x0,0x0,0x0,0xa3497ebb,0xffc6def8,0xffc6ddf6,0xffc5ddf6, + 0xffc9e0f8,0xff77abd2,0xff31af18,0xff50cd00,0xff5cd400,0xff52ce00,0xff= 3bbe00,0xe6218f03,0xd000000,0x0,0x0,0x21042043,0xfc61a0e3,0xff97c3f0, + 0xff9cc7f1,0xff9cc8f1,0xff98c4f0,0xff85b8ef,0xff469d88,0xff7de517,0xff= 87ed10,0xff7ce417,0xfe5bca14,0x811b5304,0x0,0x0,0x0,0x3e082e58, + 0xff60a7ed,0xff7fbaef,0xff8ac3f1,0xff8bc4f1,0xff83beef,0xff6caeec,0xff= 4e98b3,0xff88d54a,0xff98e343,0xff89d64a,0xf846a630,0x340c4100,0x0,0x0, + 0x0,0x1c021631,0xf867a7e3,0xff90c9f4,0xffa1d6f8,0xffa4d8f8,0xff96cef5,= 0xff82bef2,0xff65aca9,0xff8ad576,0xff86d276,0xff88d377,0xff80d072,0xd327931= 0, + 0x8000700,0x0,0x0,0x0,0x8f3f6f9f,0xffaedcf9,0xffc7effe,0xffc9f0fe,0xff= bbe5fc,0xff73b7c4,0xff45ba25,0xff51c61e,0xff50c617,0xff51c61c, + 0xff4bc120,0xff30b50c,0x62206705,0x0,0x0,0x0,0x6e1d5899,0xff81b2e7,0xf= fb4d7f4,0xffbddcf7,0xffa8cef4,0xff4698a0,0xff45c407,0xff53ce00, + 0xff59d200,0xff54cf00,0xff46c600,0xff34bb00,0xc42d9105,0x0,0x0,0x270a3= 05f,0xf567a5e3,0xffaed3f4,0xffafd4f5,0xffaed4f4,0xffaed3f4,0xff94c2f3, + 0xff4fa782,0xff6cdf00,0xff74e400,0xff6cdf00,0xff5ad300,0xff43c401,0xf7= 42b110,0x16060b00,0x0,0xa0407dba,0xff80bcf1,0xff8ec5f2,0xff92c8f2,0xff91c8f= 2, + 0xff90c6f2,0xff86bff0,0xff67a8e6,0xff80e02c,0xff95f615,0xff8aee18,0xff= 7de323,0xff76db33,0xe951a31a,0x19040a00,0xd000f28,0xf066a4de,0xff88c4f2,0xf= f97cef5, + 0xffa0d4f7,0xffa0d5f7,0xff9ad0f6,0xff8dc7f3,0xff7ebcf2,0xef6ea88b,0xd6= 79b12f,0xd271a82d,0xbb5c9221,0x8235600c,0x24060d02,0x0,0x44184c89,0xff8cc6f= 4, + 0xff99d0f6,0xffabddfa,0xffb7e6fc,0xffb8e6fc,0xffaee0fb,0xff9ed4f7,0xff= 90c9f3,0xc86697c9,0x3000000,0x4000000,0x0,0x0,0x0,0x0, + 0x2b0e3664,0xee7caed8,0xffb9e4fc,0xffcaf1fe,0xffd5f6ff,0xffd6f7ff,0xff= cbf2fe,0xffbee8fc,0xffa9d6f9,0xae5378a0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x1e020c1d,0x7634547a,0xae6a88a8,0xc4849bb4,0xc689a0b8,0xb= c7d9ab7,0x98627f9f,0x572c3e56,0xb000000,0x0,0x0, + 0x0,0x0,0x0,0x0 +}; + +static const QRgb mask_data[] =3D { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x11c84a00,0x1000000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x68d14e00,0xffda6400,0x72bf4700,0x300= 0000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x14d04d00,0xefda6400,0xfffec300,0= xf2d86300,0x24742b00, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98d14e00,0xfff3b537,0xff= fffed6, + 0xfff3b537,0xa5c04800,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x= 30cf4d00,0xfbe17803, + 0xfff1e7ad,0xffcacaba,0xfff1e7ac,0xfce07803,0x42973800,0x1000000,0x0,0= x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xc4d35300,0xfffad45c,0xffc0c0b2,0xff979797,0xffb2b2a9,0xfffad45a,0xcc= ca5000,0xa000000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x58d14e00,0xffe89410,0xfffffcbd,0xffc6c6af,0xff929292,0xffbdbda8,= 0xfffffcb9,0xffe8930e,0x69b04100,0x2000000,0x0,0x0,0x0, + 0x0,0x0,0x8cb4c00,0xe3d76000,0xfffeec6c,0xffffffbe,0xffe2e2b2,0xff8787= 87,0xffd5d5a8,0xffffffb7,0xfffeeb62,0xe8d35e00,0x17491b00,0x0, + 0x0,0x0,0x0,0x0,0x84d14e00,0xfff0b41a,0xfffffea3,0xffffffa8,0xfffbfba7= ,0xff7b7b76,0xfff6f6a0,0xffffff9c,0xfffffe8e,0xfff0b414, + 0x92bd4600,0x4000000,0x0,0x0,0x0,0x20d04d00,0xf7dd7400,0xfffff85e,0xff= ffff89,0xffffff8b,0xffffff8a,0xffc3c376,0xffffff82,0xffffff7b, + 0xffffff71,0xfffff746,0xf9db7300,0x32873200,0x0,0x0,0x0,0xa8d25200,0xf= ff6d518,0xffffff61,0xffffff65,0xffffff65,0xffecec60,0xff9f9f52, + 0xffe6e657,0xffffff54,0xffffff4c,0xffffff44,0xfff6d50e,0xb4c54c00,0x80= 00000,0x0,0x40d04e00,0xffe49001,0xfffffd2b,0xffffff3a,0xffffff3d,0xffffff3d, + 0xff9b9b33,0xff272727,0xff84842a,0xffffff2e,0xffffff28,0xffffff22,0xff= fffd18,0xffe49000,0x52a33c00,0x2000000,0xd0d55b00,0xfffcef07,0xffffff17,0xf= fffff1a, + 0xffffff1b,0xffffff1b,0xffeaea19,0xff8c8c16,0xffdbdb13,0xffffff10,0xff= ffff0d,0xffffff0a,0xffffff07,0xfffcef02,0xd7ce5800,0xc000000,0xe4d55d00,0xf= fe49204, + 0xffe4940a,0xffe4950c,0xffe4960d,0xffe4950c,0xffe4950c,0xffe4940a,0xff= e49308,0xffe49307,0xffe49205,0xffe39204,0xffe39102,0xffe39100,0xead05b00,0x= 1c000000, + 0x13582100,0x3c702900,0x40692700,0x40692700,0x40692700,0x40692700,0x40= 692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x= 40692700, + 0x29290f00,0xc000000,0x0,0x2000000,0x2000000,0x2000000,0x2000000,0x200= 0000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000, + 0x2000000,0x2000000,0x2000000,0x0 +}; + +static const QRgb others_grey_data[] =3D { + 0x0,0x0,0x0,0xa4c4c4c,0x5d676767,0x777c7c7c,0x3d555555,0x0,0x0,0x0,0x0= ,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x17535353,0xd2afafaf,0xffebebeb,0xffe5e5e5,0xfec2c2c2= ,0x906d6d6d,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xa09c9c9c,0xfff1f1f1,0xfff5f5f5,0xffe6e6e6,0x= ffd4d4d4,0xffbebebe,0x4c424242,0x117b7b7b, + 0x357d7d7d,0x177c7c7c,0x0,0x0,0x0,0x0,0x0,0x606060,0xe4b4b4b4,0xffe1e1= e1,0xffe4e4e4,0xffdcdcdc,0xffcecece,0xffc0c0c0, + 0xd9858585,0xf3d5d5d5,0xffe6e6e6,0xf8cdcdcd,0x8c828282,0x2030303,0x0,0= x0,0x0,0x0,0xdcaaaaaa,0xffd0d0d0,0xffd2d2d2,0xffcecece, + 0xffc5c5c5,0xffa3a3a3,0xffe8e8e8,0xfffbfbfb,0xfff4f4f4,0xffeaeaea,0xff= e0e0e0,0x6f767676,0x0,0x0,0x0,0x0,0x7e848484,0xffc3c3c3, + 0xffc3c3c3,0xffbfbfbf,0xffaeaeae,0xffaaaaaa,0xfff1f1f1,0xfff2f2f2,0xff= efefef,0xffe6e6e6,0xffe0e0e0,0xcba6a6a6,0x0,0x0,0x0,0xc3f3f3f, + 0xb8858585,0xff8f8f8f,0xff969696,0xff919191,0xff787878,0xffa5a5a5,0xff= e7e7e7,0xffe8e8e8,0xffe5e5e5,0xffe1e1e1,0xffdcdcdc,0xd4a6a6a6,0x0,0x0, + 0x0,0xa1959595,0xffdbdbdb,0xffe3e3e3,0xff999999,0xff7a7a7a,0xffb9b9b9,= 0xffb5b5b5,0xffdedede,0xffe0e0e0,0xffdfdfdf,0xffdbdbdb,0xffd1d1d1,0x8e89898= 9, + 0x0,0x0,0x28363636,0xfcb2b2b2,0xffdadada,0xffededed,0xfff5f5f5,0xffd5d= 5d5,0xfff5f5f5,0xffcbcbcb,0xffb7b7b7,0xffd2d2d2,0xffd3d3d3,0xffc8c8c8, + 0xffb2b2b2,0x78979797,0x0,0x0,0x694b4b4b,0xffafafaf,0xffc8c8c8,0xffd1d= 1d1,0xffd8d8d8,0xffdbdbdb,0xffb9b9b9,0xffd7d7d7,0xffe4e4e4,0xffc3c3c3, + 0xffa0a0a0,0xffb9b9b9,0xffd2d2d2,0xffdbdbdb,0x5e979797,0x0,0x70434343,= 0xff9c9c9c,0xffadadad,0xffb6b6b6,0xffbbbbbb,0xffbbbbbb,0xffb0b0b0,0xffdfdfd= f, + 0xfff5f5f5,0xfff8f8f8,0xfff2f2f2,0xfff8f8f8,0xfff6f6f6,0xffe3e3e3,0xe6= bababa,0x90b0b0b,0x30232323,0xfb767676,0xff939393,0xff9a9a9a,0xff9f9f9f,0xf= f969696, + 0xffbbbbbb,0xffdadada,0xffe3e3e3,0xffe8e8e8,0xffeaeaea,0xffe9e9e9,0xff= e5e5e5,0xffdedede,0xffc8c8c8,0x41363636,0x0,0x5a2e2e2e,0xde5b5b5b,0xfe70707= 0, + 0xff7a7a7a,0xff727272,0xffb3b3b3,0xffcbcbcb,0xffd1d1d1,0xffd6d6d6,0xff= d8d8d8,0xffd7d7d7,0xffd3d3d3,0xffcecece,0xffbfbfbf,0x57424242,0x0,0x0, + 0x4000000,0x20050505,0x33070707,0x3b181818,0xf2959595,0xffbababa,0xffb= fbfbf,0xffc3c3c3,0xffc5c5c5,0xffc4c4c4,0xffc1c1c1,0xffbcbcbc,0xfe9f9f9f,0x3= 21d1d1d, + 0x0,0x0,0x0,0x0,0x0,0x0,0x5c5f5f5f,0xf08a8a8a,0xffa7a7a7,0xffb0b0b0,0x= ffb2b2b2,0xffb0b0b0,0xffa9a9a9,0xf98e8e8e, + 0x874c4c4c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf101010,0x4a2b2b2b,0x6542= 4242,0x6c4a4a4a,0x67444444, + 0x542e2e2e,0x200f0f0f,0x0,0x0 +}; + +static const QRgb others_data[] =3D { + 0x0,0x0,0x0,0xa804618,0x5d95643a,0x77a77c52,0x3d855126,0x0,0x0,0x0,0x0= ,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x17964f11,0xd2cfb190,0xfff8efdf,0xffffeccb,0xfeedce98= ,0x909b703f,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xa0d29e66,0xfffff7e3,0xfffff8ec,0xffffedce,0x= ffffe0a9,0xfff5cd88,0x4c6f4316,0x11f72300, + 0x35fb2b00,0x17f82200,0x0,0x0,0x0,0x0,0x0,0xc15b00,0xe4ebbc7d,0xffffea= c4,0xffffecca,0xffffe5b9,0xfffedb9e,0xfff4d38d, + 0xd9c76844,0xf3f6b8b4,0xfffcdad0,0xf8f5b3a6,0x8cba524a,0x2070000,0x0,0= x0,0x0,0x0,0xdce9b56b,0xfffedda3,0xffffdea6,0xfffedb9e, + 0xfff8d592,0xffdf9f67,0xfffadad6,0xfffffaf8,0xfffef0ea,0xfffee2d6,0xff= fed4c3,0x6fac4f41,0x0,0x0,0x0,0x0,0x7ecd933c,0xfff7d390, + 0xfff6d390,0xfff3d08b,0xffe6c377,0xffe29c73,0xfffeece4,0xfffeeee7,0xff= fee9e0,0xfffddecf,0xfff9d8c8,0xcbd0927d,0x0,0x0,0x0,0xc007f00, + 0xb85db05a,0xffbbae64,0xffd4ab58,0xffd0a952,0xffba9636,0xffd9a571,0xff= fddfd2,0xfffee0d3,0xfffdddce,0xfffbd8c8,0xfff6d2c2,0xd4d3927a,0x0,0x0, + 0x0,0xa171b973,0xffd4e9ce,0xffd4f2d5,0xffb2a680,0xffdb301a,0xff9cde94,= 0xffd3c097,0xfffbd4c2,0xfffad7c6,0xfff9d6c6,0xfff6d2c0,0xfff8c2ab,0x8ec26d5= 1, + 0x0,0x0,0x28026b11,0xfc9ed391,0xffd4efc6,0xffeaf8e2,0xfff2fcee,0xffe5c= dc6,0xfff4fcee,0xffb5cbe1,0xffd19da5,0xfff9c2ab,0xfff8c5ae,0xfff9b398, + 0xffd6918f,0x785982d5,0x0,0x0,0x691d792e,0xff9edc82,0xffbdeaa7,0xffc8e= db6,0xffd0f0c0,0xffd4f2c4,0xffa8cac2,0xffbdccf2,0xffcfdefa,0xffbcb5d2, + 0xff9a91b0,0xffaba8ca,0xffaaccfb,0xffc4d1f2,0x5e6184ce,0x0,0x70196d2d,= 0xff88d663,0xff9dde7c,0xffa8e28a,0xffaee493,0xffb0e493,0xff89add8,0xffc6dbf= 8, + 0xffebf5ff,0xfff1f7ff,0xffe6f3ff,0xfff2f8ff,0xffeef6ff,0xffcfe0f8,0xe6= 94b1e1,0x9000317,0x30004626,0xfb57b03d,0xff7ed651,0xff86d75e,0xff8cd966,0xf= f7cc16b, + 0xff84aff2,0xffb6dafe,0xffc8e4ff,0xffd2eaff,0xffd6ebff,0xffd4eaff,0xff= cce6ff,0xffbee0ff,0xff96c2fb,0x410e1f5e,0x0,0x5a104c2a,0xde3b882f,0xfe51aa3= 7, + 0xff5cb83c,0xff4e9c49,0xff70a8f6,0xff98cdff,0xffa4d3ff,0xffaed7ff,0xff= b1d8ff,0xffb0d8ff,0xffa8d4ff,0xff9dcfff,0xff81bcfe,0x57132571,0x0,0x0, + 0x4000001,0x2000020a,0x3300080f,0x3b000d31,0xf24a83e0,0xff76bdff,0xff8= 0c2ff,0xff88c5ff,0xff8cc6ff,0xff8ac6ff,0xff84c2ff,0xff7abeff,0xfe5694e9,0x3= 2030738, + 0x0,0x0,0x0,0x0,0x0,0x0,0x5c1429ab,0xf03d77d8,0xff57a3f7,0xff62b0fe,0x= ff65b2ff,0xff63b1fe,0xff5aa6f9,0xf9427edb, + 0x87152a83,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000021,0x4a020554,0x650b= 167a,0x6c0e1d86,0x670c187d, + 0x5403065a,0x2000001e,0x0,0x0 +}; + +static const QRgb user_green_data[] =3D { + 0x0,0x0,0x0,0x0,0x5029,0x6c1c6e21,0xe332aa3b,0xf83ac841,0xf838c83f,0xd= a369a3b,0x5a145819,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x7e1a6c1e,0xff32da39,0xff3de341,0xff3ee045,0x= ff3ee042,0xff3de345,0xff27d930,0x68125817, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f013105,0xf721a328,0xff22de27,0xff23dd2= 7,0xff26dc26,0xff26dc2a,0xff22de27, + 0xff22de27,0xee268c2b,0x12001402,0x0,0x0,0x0,0x0,0x0,0x0,0x5c0b590f,0x= ff19b51d,0xff1ecc1e,0xff1dd31d,0xff22d41e, + 0xff1ed41e,0xff1cd21c,0xff1dcb21,0xff18b01b,0x4d093d0d,0x0,0x0,0x0,0x0= ,0x0,0x0,0x640f5f13,0xff18bc18,0xff1ec61a, + 0xff1ed119,0xff22d519,0xff22d519,0xff22ce1a,0xff1fc31b,0xff16be1a,0x5a= 0e4211,0x0,0x0,0x0,0x0,0x0,0x0,0x38033507, + 0xff1db91d,0xff21d818,0xff24e616,0xff2aec16,0xff2aec16,0xff24e416,0xff= 21d418,0xfd20b020,0x35031b05,0x0,0x0,0x0,0x0,0x0, + 0x0,0x2000000,0xbb2a702c,0xff2df018,0xff3af41c,0xff48f620,0xff46fa1c,0= xff39f21a,0xff23ef13,0xb929632c,0x4000000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x2e012703,0xfc279129,0xff3fe729,0xff5ff537,0xff5bf632= ,0xff2ef11f,0xf6298f2e,0x29010d02,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x6000e07,0xc41f7721,0xff1ee01e,0xff29dd2d,0xff22d= e27,0xff22de27,0xff2bdf34,0xff1ddf21,0xab227226, + 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d136117,0xff1bc31b,0xff1ee01e,0xf= f24e020,0xff25e220,0xff25e220,0xff20e020, + 0xff20dc20,0xff1bbf1e,0x561b571f,0x0,0x0,0x0,0x0,0x0,0x8001205,0xe2268= e29,0xff1eca1a,0xff23d41a,0xff23d81a,0xff23d81a, + 0xff23d81a,0xff23d81a,0xff24d11b,0xff1fc71b,0xd12a882c,0x4000000,0x0,0= x0,0x0,0x0,0x4a0e5012,0xff1cc818,0xff21d119,0xff25db17, + 0xff25e117,0xff24e616,0xff24e616,0xff27df19,0xff21da18,0xff22cf19,0xff= 18c418,0x3a173d19,0x0,0x0,0x0,0x0,0x982b732c,0xff1ed915, + 0xff25dd17,0xff28ec14,0xff32f018,0xff34f21a,0xff32f218,0xff2af016,0xff= 28ea14,0xff20db17,0xff1bd317,0x85316f34,0x0,0x0,0x0,0x0, + 0xbf318131,0xff22e818,0xff2aea16,0xff39ef1b,0xff44fa1a,0xff4dfa1e,0xff= 4dfa1e,0xff3ff71b,0xff30f016,0xff2ae616,0xff20e616,0xb3337936,0x0,0x0, + 0x0,0x0,0x51134b16,0xed369834,0xff2ef11f,0xff54f828,0xff67fc2c,0xff6bf= b33,0xff6ffc30,0xff5ffc28,0xff48f925,0xff30f41c,0xec33a135,0x561b3d1e, + 0x0,0x0,0x0,0x0,0x0,0x18000802,0x60113b14,0x9d315f33,0xbb417143,0xc646= 7848,0xc6467a48,0xbc417942,0x9e3c663e,0x64224225, + 0x1c020604,0x0,0x0,0x0 +}; + +static const QRgb user_grey_data[] =3D { + 0x0,0x0,0x0,0x0,0x404040,0x6c6e6e6e,0xe3b0b0b0,0xf8cecece,0xf8cccccc,0= xdaa6a6a6,0x5a575757,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x7e6b6b6b,0xffd6d6d6,0xffe6e6e6,0xffe4e4e4,0x= ffe4e4e4,0xffe6e6e6,0xffcccccc,0x68555555, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f282828,0xf79d9d9d,0xffcccccc,0xffcdcdc= d,0xffcecece,0xffcecece,0xffcccccc, + 0xffcccccc,0xee8f8f8f,0x12101010,0x0,0x0,0x0,0x0,0x0,0x0,0x5c515151,0x= ffa5a5a5,0xffbbbbbb,0xffc0c0c0,0xffc1c1c1, + 0xffc1c1c1,0xffbfbfbf,0xffbababa,0xffa0a0a0,0x4d383838,0x0,0x0,0x0,0x0= ,0x0,0x0,0x64585858,0xffaaaaaa,0xffb4b4b4, + 0xffbcbcbc,0xffbfbfbf,0xffbfbfbf,0xffbababa,0xffb2b2b2,0xffa9a9a9,0x5a= 404040,0x0,0x0,0x0,0x0,0x0,0x0,0x382e2e2e, + 0xffababab,0xffc0c0c0,0xffc9c9c9,0xffcfcfcf,0xffcecece,0xffc8c8c8,0xff= bdbdbd,0xfda6a6a6,0x35181818,0x0,0x0,0x0,0x0,0x0, + 0x0,0x2000000,0xbb7c7c7c,0xffd3d3d3,0xffd9d9d9,0xffdfdfdf,0xffdedede,0= xffd7d7d7,0xffcecece,0xb9717171,0x4000000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x2e202020,0xfc939393,0xffdadada,0xfff0f0f0,0xffededed= ,0xffdadada,0xf6949494,0x290c0c0c,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x60c0c0c,0xc4787878,0xffcbcbcb,0xffd2d2d2,0xffccc= ccc,0xffcccccc,0xffd4d4d4,0xffc9c9c9,0xab777777, + 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d5d5d5d,0xffb2b2b2,0xffcbcbcb,0xf= fcccccc,0xffcecece,0xffcecece,0xffcccccc, + 0xffcacaca,0xffafafaf,0x565c5c5c,0x0,0x0,0x0,0x0,0x0,0x80f0f0f,0xe2909= 090,0xffb7b7b7,0xffbebebe,0xffc1c1c1,0xffc1c1c1, + 0xffc1c1c1,0xffc1c1c1,0xffbdbdbd,0xffb5b5b5,0xd18f8f8f,0x4000000,0x0,0= x0,0x0,0x0,0x4a4c4c4c,0xffb3b3b3,0xffbbbbbb,0xffc2c2c2, + 0xffc7c7c7,0xffc9c9c9,0xffc9c9c9,0xffc6c6c6,0xffc1c1c1,0xffb9b9b9,0xff= b0b0b0,0x3a434343,0x0,0x0,0x0,0x0,0x987e7e7e,0xffbfbfbf, + 0xffc4c4c4,0xffcdcdcd,0xffd3d3d3,0xffd6d6d6,0xffd5d5d5,0xffd1d1d1,0xff= cbcbcb,0xffc2c2c2,0xffbbbbbb,0x85808080,0x0,0x0,0x0,0x0, + 0xbf8e8e8e,0xffcccccc,0xffcccccc,0xffd5d5d5,0xffdddddd,0xffe0e0e0,0xff= e0e0e0,0xffdbdbdb,0xffd2d2d2,0xffcacaca,0xffcacaca,0xb38a8a8a,0x0,0x0, + 0x0,0x0,0x514b4b4b,0xeda4a4a4,0xffdadada,0xffe7e7e7,0xffededed,0xfff1f= 1f1,0xfff0f0f0,0xffeaeaea,0xffe4e4e4,0xffdadada,0xeca9a9a9,0x56474747, + 0x0,0x0,0x0,0x0,0x0,0x18070707,0x603e3e3e,0x9d747474,0xbb8e8e8e,0xc698= 9898,0xc69a9a9a,0xbc959595,0x9e828282,0x64505050, + 0x1c070707,0x0,0x0,0x0 +}; + +static const QRgb user_data[] =3D { + 0x0,0x0,0x0,0x0,0x7f,0x6c2c68af,0xe384abdb,0xf8b2ccea,0xf8aecae9,0xda7= ba3d1,0x5a20508d,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x7e2a66ac,0xffb8d4f3,0xffd2e5f9,0xffd0e3f8,0x= ffcfe3f8,0xffd3e5f9,0xffa7c9f0,0x681d4e8c, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f02244d,0xf75c9ade,0xffa6cbf2,0xffa7ccf= 2,0xffa9cef2,0xffa9cdf2,0xffa6ccf2, + 0xffa6ccf2,0xee4d8bd0,0x12000d1f,0x0,0x0,0x0,0x0,0x0,0x0,0x5c124c8f,0x= ff60a4ea,0xff88bcee,0xff8fc1f0,0xff92c4f0, + 0xff92c3f0,0xff8ec0f0,0xff85baee,0xff579fe9,0x4d0f3460,0x0,0x0,0x0,0x0= ,0x0,0x0,0x64185598,0xff67acec,0xff7ab8ee, + 0xff87c1f1,0xff8cc5f2,0xff8cc5f2,0xff84c0f0,0xff76b6ed,0xff63a9ee,0x5a= 173d69,0x0,0x0,0x0,0x0,0x0,0x0,0x38052a56, + 0xff6caee9,0xff8cc6f3,0xff9cd2f6,0xffa5d8f8,0xffa4d7f8,0xff99d0f6,0xff= 88c3f2,0xfd68a7e4,0x3505152b,0x0,0x0,0x0,0x0,0x0, + 0x0,0x2000000,0xbb447bb3,0xffabdbfa,0xffb6e4fc,0xffc0ecfe,0xffbeebfe,0= xffb3e2fb,0xffa2d6f9,0xb9426e9f,0x4000000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x2e011c3e,0xfc5491d2,0xffbce2f8,0xffe1f6fe,0xffdcf5fe= ,0xffb9e0fb,0xf65790d0,0x29010b17,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x6000017,0xc43276be,0xffa2cbf3,0xffb0d1f3,0xffa6c= bf2,0xffa6cbf2,0xffb4d2f4,0xff9ec9f3,0xab3774b7, + 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d1f599b,0xff76b3ed,0xffa3ccf3,0xf= fa5cff3,0xffa7d0f4,0xffa7d0f4,0xffa5cef3, + 0xffa2ccf2,0xff71afed,0x562c578c,0x0,0x0,0x0,0x0,0x0,0x800071e,0xe24f8= fd0,0xff7ebaef,0xff8bc4f1,0xff90c7f2,0xff8fc7f2, + 0xff8fc6f2,0xff8fc6f2,0xff89c2f0,0xff7bb8ee,0xd1538dca,0x4000000,0x0,0= x0,0x0,0x0,0x4a164781,0xff77b8ef,0xff85c2f1,0xff90caf4, + 0xff98cff5,0xff9cd2f6,0xff9bd1f6,0xff97cef5,0xff8ec8f3,0xff82bff0,0xff= 72b2ee,0x3a244062,0x0,0x0,0x0,0x0,0x98447db7,0xff8ac5f4, + 0xff94ccf4,0xffa1d6f8,0xffabddfa,0xffb0e0fb,0xffafe0fb,0xffa8dbfa,0xff= 9ed4f7,0xff90c9f4,0xff83c0f3,0x854d7cb2,0x0,0x0,0x0,0x0, + 0xbf5a8fc1,0xffa1d2f6,0xffa0d6f7,0xffafe0fa,0xffbceafe,0xffc2eefe,0xff= c2eefe,0xffb9e8fd,0xffaaddfa,0xff9ed3f6,0xff9dd0f6,0xb35a88ba,0x0,0x0, + 0x0,0x0,0x511f4776,0xed77a7d1,0xffb8e0fb,0xffcff1fe,0xffdaf8ff,0xffe2f= 9ff,0xffe0f9ff,0xffd5f6ff,0xffcaeefe,0xffb8e1fc,0xec7ca9d6,0x562c4462, + 0x0,0x0,0x0,0x0,0x0,0x1800030d,0x601b3a61,0x9d4f7198,0xbb6e8cad,0xc67d= 96b3,0xc67d98b6,0xbc7494b5,0x9e6180a3,0x64364c69, + 0x1c040409,0x0,0x0,0x0 +}; + +static const QRgb yes_data[] =3D { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x11049c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x1005a200,0x800ba600,0xd512a700,0xe1009d00,0x34007700,0x1= 000000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x8009500,0x78009b00,0xf0039f03,0xe2009800,0x46003700,0xbb= 009300,0xeb11a111,0x35006f00,0x1000000,0x0,0x0, + 0x0,0x0,0x0,0x8008d00,0x70009300,0xe819ab19,0xff3ec63e,0xd4099109,0x45= 002c00,0xf000000,0x6f008900,0xff33d633,0xeb0a9e0a,0x35006800, + 0x1000000,0x0,0x0,0x4008900,0x6c008a00,0xe8099e09,0xff2cd52c,0xff3bd93= b,0xcb048404,0x3c001c00,0xc000000,0x0,0x28007a00,0xff0abc0a, + 0xff10f410,0xeb019701,0x35006100,0x5006d00,0x60008100,0xdc009800,0xff0= 6d206,0xff13fd13,0xff11ce11,0xc2017801,0x32000b00,0xa000000,0x0,0x0, + 0x1000000,0xde009100,0xff00f700,0xff00eb00,0xeb008e00,0xde008700,0xff0= 0c400,0xff00f500,0xff00f700,0xff00c100,0xae006700,0x30000b00,0x8000000,0x0, + 0x0,0x0,0x0,0x97007100,0xff00dc00,0xff00eb00,0xff00e500,0xff00e700,0xf= f00eb00,0xff00eb00,0xff00a800,0xa2005c00,0x29000000,0x6000000, + 0x0,0x0,0x0,0x0,0x0,0x4c006600,0xff00af00,0xff00de00,0xff00de00,0xff00= de00,0xff00dc00,0xff009600,0x96005100,0x24000000, + 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa004e00,0xf8008200,0xff00d200,0xff= 00d200,0xff00ce00,0xfc008700,0x80004100, + 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb005f00,0xff00= c300,0xff00c100,0xf6007500, + 0x76003800,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x= 6f005800,0xff009700, + 0xf4006d00,0x6c003200,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0= ,0x0,0x0,0x0, + 0x28005300,0xed005900,0x5a002800,0x16000000,0x1000000,0x0,0x0,0x0,0x0,= 0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,= 0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0 +}; + +static const QRgb yespartial_data[] =3D { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x114e4e4e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x10515151,0x80535353,0xd5535353,0xe14e4e4e,0x343b3b3b,0x1= 000000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x84a4a4a,0x784d4d4d,0x9e515151,0xe24c4c4c,0x461b1b1b,0xbb= 494949,0xeb595959,0x35373737,0x1000000,0x0,0x0, + 0x0,0x0,0x0,0x8464646,0x70494949,0xe8626262,0x93828282,0xc34d4d4d,0x45= 161616,0xf000000,0x6f444444,0x8c848484,0xcf545454,0x35343434, + 0x1000000,0x0,0x0,0x4444444,0x6c454545,0xe5535353,0x57808080,0x5e8a8a8= a,0xcb444444,0x3c0e0e0e,0xc000000,0x0,0x283d3d3d,0xa7636363, + 0x32828282,0xeb4c4c4c,0x35303030,0x5363636,0x60404040,0xdc4c4c4c,0x756= c6c6c,0x2b888888,0x7b6f6f6f,0xc23c3c3c,0x32050505,0xa000000,0x0,0x0, + 0x1000000,0xde484848,0x3c7b7b7b,0x1f757575,0xeb474747,0xde434343,0x806= 26262,0x3c7a7a7a,0x337b7b7b,0x56606060,0xae333333,0x30050505,0x8000000,0x0, + 0x0,0x0,0x0,0x97383838,0x4c6e6e6e,0xa757575,0x3727272,0x24737373,0x2b7= 57575,0x27757575,0x75545454,0x952e2e2e,0x29000000,0x6000000, + 0x0,0x0,0x0,0x0,0x0,0x4c333333,0x8e575757,0x1c6f6f6f,0x46f6f6f,0xb6f6f= 6f,0x2b6e6e6e,0x994b4b4b,0x85282828,0x24000000, + 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa272727,0xdc414141,0x3d696969,0x11= 696969,0x1e676767,0x91434343,0x77202020, + 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb2f2f2f,0x5d61= 6161,0x36606060,0x893a3a3a, + 0x761c1c1c,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x= 6f2c2c2c,0x9a4b4b4b, + 0x9b363636,0x6c191919,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0= ,0x0,0x0,0x0, + 0x28292929,0xed2c2c2c,0x5a141414,0x16000000,0x1000000,0x0,0x0,0x0,0x0,= 0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,= 0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0 +}; + +static struct EmbedImage { + int width, height, depth; + const unsigned char *data; + int numColors; + const QRgb *colorTable; + bool alpha; + const char *name; +} embed_image_vec[] =3D { + { 16, 16, 32, (const unsigned char*)group_grey_data, 0, 0, TRUE, "grou= p-grey" }, + { 16, 16, 32, (const unsigned char*)group_data, 0, 0, TRUE, "group" }, + { 16, 16, 32, (const unsigned char*)mask_data, 0, 0, TRUE, "mask" }, + { 16, 16, 32, (const unsigned char*)others_grey_data, 0, 0, TRUE, "oth= ers-grey" }, + { 16, 16, 32, (const unsigned char*)others_data, 0, 0, TRUE, "others" = }, + { 16, 16, 32, (const unsigned char*)user_green_data, 0, 0, TRUE, "user= =2Dgreen" }, + { 16, 16, 32, (const unsigned char*)user_grey_data, 0, 0, TRUE, "user-= grey" }, + { 16, 16, 32, (const unsigned char*)user_data, 0, 0, TRUE, "user" }, + { 16, 16, 32, (const unsigned char*)yes_data, 0, 0, TRUE, "yes" }, + { 16, 16, 32, (const unsigned char*)yespartial_data, 0, 0, TRUE, "yesp= artial" }, + { 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +static const QImage& qembed_findImage( const QString& name ) +{ + static QDict dict; + QImage* img =3D dict.find( name ); + if ( !img ) { + for ( int i =3D 0; embed_image_vec[i].data; i++ ) { + if ( strcmp(embed_image_vec[i].name, name.latin1()) =3D=3D 0 ) { + img =3D new QImage((uchar*)embed_image_vec[i].data, + embed_image_vec[i].width, + embed_image_vec[i].height, + embed_image_vec[i].depth, + (QRgb*)embed_image_vec[i].colorTable, + embed_image_vec[i].numColors, + QImage::BigEndian ); + if ( embed_image_vec[i].alpha ) + img->setAlphaBuffer( TRUE ); + dict.insert( name, img ); + break; + } + } + if ( !img ) { + static QImage dummy; + return dummy; + } + } + return *img; +} + +#endif Index: kfile/kpropertiesdialog.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/kpropertiesdialog.cpp (.../KDE/3.5/kdelibs/kio) (revision 44374= 9) +++ kfile/kpropertiesdialog.cpp (.../work/posix-acl-support/kdelibs/kio) (r= evision 443749) @@ -46,10 +46,14 @@ extern "C" { #include #include #include +#include +#include } #include #include #include +#include +#include =20 #include #include @@ -67,6 +71,8 @@ extern "C" { #include #include #include +#include +#include =20 #include #include @@ -106,11 +112,13 @@ extern "C" { #include #include #include +#include #include "kfilesharedlg.h" =20 #include "kpropertiesdesktopbase.h" #include "kpropertiesdesktopadvbase.h" #include "kpropertiesmimetypebase.h" +#include "kacleditwidget.h" =20 #include "kpropertiesdialog.h" =20 @@ -1457,6 +1465,9 @@ public: KFilePermissionsPropsPlugin::PermissionsMode pmode; bool canChangePermissions; bool isIrregular; + bool hasExtendedACL; + KACL extendedACL; + KACL defaultACL; }; =20 #define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR) @@ -1511,6 +1522,9 @@ KFilePermissionsPropsPlugin::KFilePermis d->isIrregular =3D isIrregular(permissions, isDir, isLink); strOwner =3D item->user(); strGroup =3D item->group(); + d->hasExtendedACL =3D item->hasExtendedACL(); + d->extendedACL =3D item->ACL(); + d->defaultACL =3D item->defaultACL(); =20 if ( properties->items().count() > 1 ) { @@ -1523,6 +1537,7 @@ KFilePermissionsPropsPlugin::KFilePermis d->isIrregular |=3D isIrregular((*it)->permissions(), (*it)->isDir() =3D=3D isDir, (*it)->isLink() =3D=3D isLink); + d->hasExtendedACL =3D d->hasExtendedACL || (*it)->hasExtendedACL(); if ( (*it)->isLink() !=3D isLink ) isLink =3D false; if ( (*it)->isDir() !=3D isDir ) @@ -1819,23 +1834,28 @@ void KFilePermissionsPropsPlugin::slotSh QGroupBox *gb; QGridLayout *gl; =20 + QVBox *mainVBox =3D dlg.makeVBoxMainWidget(); + // Group: Access Permissions =2D gb =3D new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), &d= lg ); + gb =3D new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), main= VBox ); gb->layout()->setSpacing(KDialog::spacingHint()); gb->layout()->setMargin(KDialog::marginHint()); =2D dlg.setMainWidget(gb); =20 gl =3D new QGridLayout (gb->layout(), 6, 6); gl->addRowSpacing(0, 10); =20 =2D l =3D new QLabel(i18n("Class"), gb); + QValueVector theNotSpecials; + + l =3D new QLabel(i18n("Class"), gb ); gl->addWidget(l, 1, 0); + theNotSpecials.append( l ); =20 if (isDir) l =3D new QLabel( i18n("Show\nEntries"), gb ); else l =3D new QLabel( i18n("Read"), gb ); gl->addWidget (l, 1, 1); + theNotSpecials.append( l ); QString readWhatsThis; if (isDir) readWhatsThis =3D i18n("This flag allows viewing the content of the fo= lder."); @@ -1848,6 +1868,7 @@ void KFilePermissionsPropsPlugin::slotSh else l =3D new QLabel( i18n("Write"), gb ); gl->addWidget (l, 1, 2); + theNotSpecials.append( l ); QString writeWhatsThis; if (isDir) writeWhatsThis =3D i18n("This flag allows adding, renaming and deletin= g of files. " @@ -1866,6 +1887,7 @@ void KFilePermissionsPropsPlugin::slotSh execWhatsThis =3D i18n("Enable this flag to allow executing the file a= s a program."); } QWhatsThis::add(l, execWhatsThis); + theNotSpecials.append( l ); // GJ: Add space between normal and special modes QSize size =3D l->sizeHint(); size.setWidth(size.width() + 15); @@ -1885,14 +1907,17 @@ void KFilePermissionsPropsPlugin::slotSh =20 cl[0] =3D new QLabel( i18n("User"), gb ); gl->addWidget (cl[0], 2, 0); + theNotSpecials.append( cl[0] ); =20 cl[1] =3D new QLabel( i18n("Group"), gb ); gl->addWidget (cl[1], 3, 0); + theNotSpecials.append( cl[1] ); =20 cl[2] =3D new QLabel( i18n("Others"), gb ); gl->addWidget (cl[2], 4, 0); + theNotSpecials.append( cl[2] ); =20 =2D l =3D new QLabel(i18n("Set UID"), gb); + l =3D new QLabel(i18n("Set UID"), gb ); gl->addWidget(l, 2, 5); QString setUidWhatsThis; if (isDir) @@ -1959,7 +1984,8 @@ void KFilePermissionsPropsPlugin::slotSh QCheckBox *cba[3][4]; for (int row =3D 0; row < 3 ; ++row) { for (int col =3D 0; col < 4; ++col) { =2D QCheckBox *cb =3D new QCheckBox(gb); + QCheckBox *cb =3D new QCheckBox( gb ); + if ( col !=3D 3 ) theNotSpecials.append( cb ); cba[row][col] =3D cb; cb->setChecked(aPermissions & fperm[row][col]); if ( aPartialPermissions & fperm[row][col] ) @@ -2000,6 +2026,26 @@ void KFilePermissionsPropsPlugin::slotSh } gl->setColStretch(6, 10); =20 + KACLEditWidget *extendedACLs =3D 0; + bool fileSystemSupportsACLs =3D false; + + // FIXME make it work with partial entries + if ( properties->items().count() =3D=3D 1 ) { + QCString pathCString =3D QFile::encodeName( properties->item()->url().= path() ); + fileSystemSupportsACLs =3D + getxattr( pathCString.data(), "system.posix_acl_access", NULL, 0 ) >= =3D 0 || errno =3D=3D ENODATA; + } + if ( fileSystemSupportsACLs ) { + std::for_each( theNotSpecials.begin(), theNotSpecials.end(), std::mem_= fun( &QWidget::hide ) ); + extendedACLs =3D new KACLEditWidget( mainVBox ); + if ( d->extendedACL.isValid() && d->extendedACL.isExtended() ) + extendedACLs->setACL( d->extendedACL ); + else + extendedACLs->setACL( KACL( aPermissions ) ); + + if ( d->defaultACL.isValid() ) + extendedACLs->setDefaultACL( d->defaultACL ); + } if (dlg.exec() !=3D KDialogBase::Accepted) return; =20 @@ -2033,6 +2079,15 @@ void KFilePermissionsPropsPlugin::slotSh permissions =3D orPermissions; d->partialPermissions =3D andPermissions; =20 + // override with the acls, if present + if ( extendedACLs ) { + d->extendedACL =3D extendedACLs->getACL(); + d->defaultACL =3D extendedACLs->getDefaultACL(); + d->hasExtendedACL =3D d->extendedACL.isExtended() || d->defaultACL.isV= alid(); + permissions =3D d->extendedACL.basePermissions(); + permissions |=3D ( andPermissions | orPermissions ) & ( S_ISUID|S_ISGI= D|S_ISVTX ); + } + emit changed(); updateAccessControls(); } @@ -2168,9 +2223,9 @@ void KFilePermissionsPropsPlugin::update enableAccessControls(false); break; case PermissionsOnlyFiles: =2D enableAccessControls(d->canChangePermissions && !d->isIrregular); + enableAccessControls(d->canChangePermissions && !d->isIrregular && !d-= >hasExtendedACL); if (d->canChangePermissions) =2D d->explanationLabel->setText(d->isIrregular ? + d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ? i18n("This file uses advanced permissions", "These files use advanced permissions.", properties->items().count()) : ""); @@ -2184,9 +2239,14 @@ void KFilePermissionsPropsPlugin::update } break; case PermissionsOnlyDirs: =2D enableAccessControls(d->canChangePermissions && !d->isIrregular); + enableAccessControls(d->canChangePermissions && !d->isIrregular && !d-= >hasExtendedACL); + // if this is a dir, and we can change permissions, don't dis-allow=20 + // recursive, we can do that for ACL setting. + if ( d->cbRecursive ) + d->cbRecursive->setEnabled( d->canChangePermissions && !d->isIrregu= lar ); + if (d->canChangePermissions) =2D d->explanationLabel->setText(d->isIrregular ? + d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ? i18n("This folder uses advanced permissions.", "These folders use advanced permissions.", properties->items().count()) : ""); @@ -2200,9 +2260,9 @@ void KFilePermissionsPropsPlugin::update } break; case PermissionsMixed: =2D enableAccessControls(d->canChangePermissions && !d->isIrregular); + enableAccessControls(d->canChangePermissions && !d->isIrregular && !d-= >hasExtendedACL); if (d->canChangePermissions) =2D d->explanationLabel->setText(d->isIrregular ? + d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ? i18n("These files use advanced permissions.") : ""); break; if (d->partialPermissions & S_ISVTX) { @@ -2348,12 +2408,22 @@ void KFilePermissionsPropsPlugin::applyC } } =20 =2D if ( !owner.isEmpty() || !group.isEmpty() || recursive || permissionCh= ange) =2D { + const bool ACLChange =3D ( d->extendedACL !=3D properties->item()->ACL(= ) ); + const bool defaultACLChange =3D ( d->defaultACL !=3D properties->item()-= >defaultACL() ); + + if ( owner.isEmpty() && group.isEmpty() && !recursive=20 + && !permissionChange && !ACLChange && !defaultACLChange ) + return; + KIO::Job * job; if (files.count() > 0) { job =3D KIO::chmod( files, orFilePermissions, ~andFilePermissions, owner, group, false ); + if ( ACLChange ) + job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extended= ACL.asString():"ACL_DELETE" ); + if ( defaultACLChange ) + job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->d= efaultACL.asString():"ACL_DELETE" ); + connect( job, SIGNAL( result( KIO::Job * ) ), SLOT( slotChmodResult( KIO::Job * ) ) ); // Wait for job @@ -2365,6 +2435,11 @@ void KFilePermissionsPropsPlugin::applyC if (dirs.count() > 0) { job =3D KIO::chmod( dirs, orDirPermissions, ~andDirPermissions, owner, group, recursive ); + if ( ACLChange ) + job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extended= ACL.asString():"ACL_DELETE" ); + if ( defaultACLChange ) + job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->d= efaultACL.asString():"ACL_DELETE" ); + connect( job, SIGNAL( result( KIO::Job * ) ), SLOT( slotChmodResult( KIO::Job * ) ) ); // Wait for job @@ -2373,7 +2448,6 @@ void KFilePermissionsPropsPlugin::applyC qApp->enter_loop(); qt_leave_modal(&dummy); } =2D } } =20 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job ) Index: kfile/kacleditwidget_p.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/kacleditwidget_p.h (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kfile/kacleditwidget_p.h (.../work/posix-acl-support/kdelibs/kio) (revi= sion 443749) @@ -0,0 +1,185 @@ +/*************************************************************************= ** + * Copyright (C) 2005 by Sean Harmer = * + * Till Adam = * + * = * + * This program is free software; you can redistribute it and/or modify = * + * it under the terms of the GNU General Public License as published by = * + * the Free Software Foundation; either version 2 of the License, or = * + * (at your option) any later version. = * + * = * + * This program is distributed in the hope that it will be useful, = * + * but WITHOUT ANY WARRANTY; without even the implied warranty of = * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the = * + * GNU General Public License for more details. = * + * = * + * You should have received a copy of the GNU General Public License = * + * along with this program; if not, write to the = * + * Free Software Foundation, Inc., = * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. = * + *************************************************************************= **/ +#ifndef KACLEDITWIDGET_P_H +#define KACLEDITWIDGET_P_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +class KACLListViewItem; +class QPushButton; +class QVButtonGroup; +class KACLListView; +class QWidgetStack; +class QCheckBox; + +/** +@author Sean Harmer +*/ +class KACLListView : public KListView +{ +Q_OBJECT + friend class KACLListViewItem; +public: + enum Types + { + OWNER_IDX =3D 0, + GROUP_IDX, + OTHERS_IDX, + MASK_IDX, + NAMED_USER_IDX, + NAMED_GROUP_IDX, + LAST_IDX + }; + enum EntryType { User =3D 1, + Group =3D 2, + Others =3D 4, + Mask =3D 8, + NamedUser =3D 16, + NamedGroup =3D 32, + AllTypes =3D 63 }; + + KACLListView( QWidget* parent =3D 0, const char* name =3D 0 ); + ~KACLListView(); + + bool hasMaskEntry() const { return m_hasMask; } + bool hasDefaultEntries() const; + bool allowDefaults() const { return m_allowDefaults; } + void setAllowDefaults( bool v ) { m_allowDefaults =3D v; } + unsigned short maskPermissions() const; + void setMaskPermissions( unsigned short maskPerms ); + acl_perm_t maskPartialPermissions() const; + void setMaskPartialPermissions( acl_perm_t maskPerms ); + + const KACLListViewItem* findDefaultItemByType( EntryType type ) const; + const KACLListViewItem* findItemByType( EntryType type, + bool defaults =3D false ) cons= t; + unsigned short calculateMaskValue( bool defaults ) const; + void calculateEffectiveRights(); + + QStringList allowedUsers( bool defaults, KACLListViewItem *allowedItem= =3D 0 ); + QStringList allowedGroups( bool defaults, KACLListViewItem *allowedIte= m =3D 0 ); + + const KACL getACL() const { return getACL(); } + KACL getACL(); + + const KACL getDefaultACL() const { return getDefaultACL(); } + KACL getDefaultACL(); + +public slots: + void slotAddEntry(); + void slotEditEntry(); + void slotRemoveEntry(); + void setACL( const KACL &anACL ); + void setDefaultACL( const KACL &anACL ); + +protected slots: + void entryClicked( QListViewItem* pItem, const QPoint& pt, int col ); +protected: + void contentsMousePressEvent( QMouseEvent * e ); + +private: + void fillItemsFromACL( const KACL &pACL, bool defaults =3D false ); + KACL itemsToACL( bool defaults ) const; + + KACL m_ACL; + KACL m_defaultACL; + unsigned short m_mask; + bool m_hasMask; + bool m_allowDefaults; + QStringList m_allUsers; + QStringList m_allGroups; +}; + +class EditACLEntryDialog : public KDialogBase +{ + Q_OBJECT +public: + EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item, + const QStringList &users, + const QStringList &groups, + const QStringList &defaultUsers, + const QStringList &defaultGroups, + int allowedTypes =3D KACLListView::AllTypes, + int allowedDefaultTypes =3D KACLListView::AllTypes, + bool allowDefault =3D false ); + KACLListViewItem* item() const { return m_item; } +public slots: + void slotOk(); + void slotSelectionChanged( int id ); +private slots: + void slotUpdateAllowedUsersAndGroups(); + void slotUpdateAllowedTypes(); +private: + KACLListView *m_listView; + KACLListViewItem *m_item; + QStringList m_users; + QStringList m_groups; + QStringList m_defaultUsers; + QStringList m_defaultGroups; + int m_allowedTypes; + int m_allowedDefaultTypes; + QVButtonGroup *m_buttonGroup; + QComboBox *m_usersCombo; + QComboBox *m_groupsCombo; + QWidgetStack *m_widgetStack; + QCheckBox *m_defaultCB; +}; + + +class KACLListViewItem : public KListViewItem +{ +public: + KACLListViewItem( QListView* parent, KACLListView::EntryType type, + unsigned short value, + bool defaultEntry, + const QString& qualifier =3D QString::null ); + virtual ~KACLListViewItem(); + virtual QString key( int column, bool ascending ) const; + + void calcEffectiveRights(); + + void togglePerm( acl_perm_t perm ); + + virtual void paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ); + + void updatePermPixmaps(); + void repaint(); + + KACLListView::EntryType type; + unsigned short value; + bool isDefault; + QString qualifier; + bool isPartial; + +private: + KACLListView* m_pACLListView; +}; + + +#endif Index: kfile/kacleditwidget.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/kacleditwidget.cpp (.../KDE/3.5/kdelibs/kio) (revision 0) +++ kfile/kacleditwidget.cpp (.../work/posix-acl-support/kdelibs/kio) (revi= sion 443749) @@ -0,0 +1,999 @@ +/*************************************************************************= ** + * Copyright (C) 2005 by Sean Harmer = * + * Till Adam = * + * = * + * This program is free software; you can redistribute it and/or modify = * + * it under the terms of the GNU General Public License as published by = * + * the Free Software Foundation; either version 2 of the License, or = * + * (at your option) any later version. = * + * = * + * This program is distributed in the hope that it will be useful, = * + * but WITHOUT ANY WARRANTY; without even the implied warranty of = * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the = * + * GNU General Public License for more details. = * + * = * + * You should have received a copy of the GNU General Public License = * + * along with this program; if not, write to the = * + * Free Software Foundation, Inc., = * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. = * + *************************************************************************= **/ +#include "kacleditwidget.h" +#include "kacleditwidget_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef HAVE_ACL_LIBACL_H +# include +#endif +extern "C" { +#include +#include +} +#include + +#include "images.h" + +static const struct { + const char* label; + const char* pixmap; +} s_itemAttributes[] =3D { + { I18N_NOOP( "Owner" ), "user-grey" }, + { I18N_NOOP( "Owning Group" ), "group-grey" }, + { I18N_NOOP( "Others" ), "others-grey" }, + { I18N_NOOP( "Mask" ), "mask" }, + { I18N_NOOP( "Named User" ), "user" }, + { I18N_NOOP( "Named Group" ), "group" }, +}; + +KACLEditWidget::KACLEditWidget( QWidget *parent, const char *name ) + :QWidget( parent, name ) +{ + QHBox *hbox =3D new QHBox( parent ); + m_listView =3D new KACLListView( hbox, "acl_listview" ); + connect( m_listView, SIGNAL( selectionChanged() ), + this, SLOT( slotUpdateButtons() ) ); + QVBox *vbox =3D new QVBox( hbox ); + vbox->setSpacing( KDialog::spacingHint() ); + m_AddBtn =3D new QPushButton( i18n( "Add Entry" ), vbox, "add_entry_bu= tton" ); + connect( m_AddBtn, SIGNAL( clicked() ), m_listView, SLOT( slotAddEntry= () ) ); + m_EditBtn =3D new QPushButton( i18n( "Edit Entry" ), vbox, "edit_entry= _button" ); + connect( m_EditBtn, SIGNAL( clicked() ), m_listView, SLOT( slotEditEnt= ry() ) ); + m_DelBtn =3D new QPushButton( i18n( "Delete Entry" ), vbox, "delete_en= try_button" ); + connect( m_DelBtn, SIGNAL( clicked() ), m_listView, SLOT( slotRemoveEn= try() ) ); + QWidget *spacer =3D new QWidget( vbox ); + spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ); + slotUpdateButtons(); +} + +void KACLEditWidget::slotUpdateButtons() +{ + int selectedItemsCount =3D 0; + QListViewItemIterator it( m_listView, QListViewItemIterator::Selected = ); + while ( it.current() ) { + ++it; + if ( ++selectedItemsCount > 1 ) + break; + } + m_EditBtn->setEnabled( selectedItemsCount =3D=3D 1 ); + m_DelBtn->setEnabled( selectedItemsCount > 0 ); +} + +KACL KACLEditWidget::getACL() const +{ + return m_listView->getACL(); +} + +KACL KACLEditWidget::getDefaultACL() const +{ + return m_listView->getDefaultACL(); +} + +void KACLEditWidget::setACL( const KACL &acl ) +{ + return m_listView->setACL( acl ); +} + +void KACLEditWidget::setDefaultACL( const KACL &acl ) +{ + return m_listView->setDefaultACL( acl ); +} + + +KACLListViewItem::KACLListViewItem( QListView* parent, + KACLListView::EntryType _type, + unsigned short _value, bool defaults, + const QString& _qualifier ) + : KListViewItem( parent, parent->lastItem() ), // we want to append + type( _type ), value( _value ), isDefault( defaults ), + qualifier( _qualifier ), isPartial( false ) +{ + m_pACLListView =3D dynamic_cast( parent ); + repaint(); +} + + +KACLListViewItem::~ KACLListViewItem() +{ + +} + +QString KACLListViewItem::key( int, bool ) const +{ + QString key; + if ( !isDefault ) + key =3D "A"; + else + key =3D "B"; + switch ( type ) + { + case KACLListView::User: + key +=3D "A"; + break; + case KACLListView::Group: + key +=3D "B"; + break; + case KACLListView::Others: + key +=3D "C"; + break; + case KACLListView::Mask: + key +=3D "D"; + break; + case KACLListView::NamedUser: + key +=3D "E" + text( 1 ); + break; + case KACLListView::NamedGroup: + key +=3D "F" + text( 1 ); + break; + default: + key +=3D text( 0 ); + break; + } + return key; +} + +void KACLListViewItem::paintCell( QPainter* p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QColorGroup mycg =3D cg; + if ( isDefault ) { + mycg.setColor( QColorGroup::Text, QColor( 0, 0, 255 ) ); + } + if ( isPartial ) { + QFont font =3D p->font(); + font.setItalic( true ); + mycg.setColor( QColorGroup::Text, QColor( 100, 100, 100 ) ); + p->setFont( font ); + } + KListViewItem::paintCell( p, mycg, column, width, alignment ); + + KACLListViewItem *below =3D0; + if ( itemBelow() ) + below =3D static_cast( itemBelow() ); + const bool lastUser =3D type =3D=3D KACLListView::NamedUser && below &= & below->type =3D=3D KACLListView::NamedGroup; + const bool lastNonDefault =3D !isDefault && below && below->isDefault; + if ( type =3D=3D KACLListView::Mask || lastUser || lastNonDefault ) + { + p->setPen( QPen( Qt::gray, 0, QPen::DotLine ) ); + if ( type =3D=3D KACLListView::Mask ) + p->drawLine( 0, 0, width - 1, 0 ); + p->drawLine( 0, height() - 1, width - 1, height() - 1 ); + } +} + + +void KACLListViewItem::updatePermPixmaps() +{ + unsigned int partialPerms =3D value; + + if ( value & ACL_READ ) + setPixmap( 2, *QPixmapCache::find("yes") ); + else if ( partialPerms & ACL_READ ) + setPixmap( 2, *QPixmapCache::find("yespartial") ); + else + setPixmap( 2, QPixmap() ); + + if ( value & ACL_WRITE ) + setPixmap( 3, *QPixmapCache::find("yes") ); + else if ( partialPerms & ACL_WRITE ) + setPixmap( 3, *QPixmapCache::find("yespartial") ); + else + setPixmap( 3, QPixmap() ); + + if ( value & ACL_EXECUTE ) + setPixmap( 4, *QPixmapCache::find("yes") ); + else if ( partialPerms & ACL_EXECUTE ) + setPixmap( 4, *QPixmapCache::find("yespartial") ); + else + setPixmap( 4, QPixmap() ); +} + +void KACLListViewItem::repaint() +{ + int idx =3D 0; + switch ( type ) + { + case KACLListView::User: + idx =3D KACLListView::OWNER_IDX; + break; + case KACLListView::Group: + idx =3D KACLListView::GROUP_IDX; + break; + case KACLListView::Others: + idx =3D KACLListView::OTHERS_IDX; + break; + case KACLListView::Mask: + idx =3D KACLListView::MASK_IDX; + break; + case KACLListView::NamedUser: + idx =3D KACLListView::NAMED_USER_IDX; + break; + case KACLListView::NamedGroup: + idx =3D KACLListView::NAMED_GROUP_IDX; + break; + default: + idx =3D KACLListView::OWNER_IDX; + break; + } + QPixmap *pic =3D QPixmapCache::find( s_itemAttributes[idx].pixmap ); + assert( pic ); + setPixmap( 0, *pic ); + setText( 0, s_itemAttributes[idx].label ); + if ( isDefault ) + setText( 0, text( 0 ) + i18n( " (Default)" ) ); + setText( 1, qualifier ); + // Set the pixmaps for which of the perms are set + updatePermPixmaps(); +} + +void KACLListViewItem::calcEffectiveRights() +{ + QString strEffective =3D QString( "---" ); + + // Do we need to worry about the mask entry? It applies to named users, + // owning group, and named groups + if ( m_pACLListView->hasMaskEntry() + && ( type =3D=3D KACLListView::NamedUser + || type =3D=3D KACLListView::Group + || type =3D=3D KACLListView::NamedGroup )=20 + && !isDefault ) + { + + strEffective[0] =3D ( m_pACLListView->maskPermissions() & value & = ACL_READ ) ? 'r' : '-'; + strEffective[1] =3D ( m_pACLListView->maskPermissions() & value & = ACL_WRITE ) ? 'w' : '-'; + strEffective[2] =3D ( m_pACLListView->maskPermissions() & value & = ACL_EXECUTE ) ? 'x' : '-'; +/* + // What about any partial perms? + if ( maskPerms & partialPerms & ACL_READ || // Partial perms on en= try + maskPartialPerms & perms & ACL_READ || // Partial perms on ma= sk + maskPartialPerms & partialPerms & ACL_READ ) // Partial perms= on mask and entry + strEffective[0] =3D 'R'; + if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on e= ntry + maskPartialPerms & perms & ACL_WRITE || // Partial perms on m= ask + maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perm= s on mask and entry + strEffective[1] =3D 'W'; + if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on= entry + maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on= mask + maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial pe= rms on mask and entry + strEffective[2] =3D 'X'; +*/ + } + else + { + // No, the effective value are just the value in this entry + strEffective[0] =3D ( value & ACL_READ ) ? 'r' : '-'; + strEffective[1] =3D ( value & ACL_WRITE ) ? 'w' : '-'; + strEffective[2] =3D ( value & ACL_EXECUTE ) ? 'x' : '-'; + + /* + // What about any partial perms? + if ( partialPerms & ACL_READ ) + strEffective[0] =3D 'R'; + if ( partialPerms & ACL_WRITE ) + strEffective[1] =3D 'W'; + if ( partialPerms & ACL_EXECUTE ) + strEffective[2] =3D 'X'; + */ + } + setText( 5, strEffective ); +} + + +void KACLListViewItem::togglePerm( acl_perm_t perm ) +{ + value ^=3D perm; // Toggle the perm + if ( type =3D=3D KACLListView::Mask && !isDefault ) { + m_pACLListView->setMaskPermissions( value ); + } + calcEffectiveRights(); + updatePermPixmaps(); +/* + // If the perm is in the partial perms then remove it. i.e. Once + // a user changes a partial perm it then applies to all selected files. + if ( m_pEntry->m_partialPerms & perm ) + m_pEntry->m_partialPerms ^=3D perm; + + m_pEntry->setPartialEntry( false ); + // Make sure that all entries have their effective rights calculated if + // we are changing the ACL_MASK entry. + if ( type =3D=3D Mask ) + { + m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerm= s ); + m_pACLListView->setMaskPermissions( value ); + m_pACLListView->calculateEffectiveRights(); + } +*/ +} + + + +EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListVi= ewItem *item, + const QStringList &users, + const QStringList &groups, + const QStringList &defaultUsers, + const QStringList &defaultGroups, + int allowedTypes, int allowedDefau= ltTypes, + bool allowDefaults ) + : KDialogBase( listView, "edit_entry_dialog", true, + i18n( "Edit ACL entry" ), KDialogBase::Ok|KDialogBase::Cance= l, + KDialogBase::Ok, false ),=20 + m_listView( listView ), m_item( item ), m_users( users ), m_groups= ( groups ), + m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ), + m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefa= ultTypes ), + m_defaultCB( 0 ) +{ + QWidget *page =3D new QWidget( this ); + setMainWidget( page ); + QVBoxLayout *mainLayout =3D new QVBoxLayout( page, marginHint(), spaci= ngHint(), "mainLayout" ); + m_buttonGroup =3D new QVButtonGroup( i18n("Entry type"), page, "bg" ); + + if ( allowDefaults ) { + m_defaultCB =3D new QCheckBox( i18n("Default for new files in this= directory"), page, "defaultCB" ); + mainLayout->addWidget( m_defaultCB ); + connect( m_defaultCB, SIGNAL( toggled( bool ) ), + this, SLOT( slotUpdateAllowedUsersAndGroups() ) ); + connect( m_defaultCB, SIGNAL( toggled( bool ) ), + this, SLOT( slotUpdateAllowedTypes() ) ); + + } + + mainLayout->addWidget( m_buttonGroup ); + + QRadioButton *ownerType =3D new QRadioButton( i18n("Owner"), m_buttonG= roup, "ownerType" ); + m_buttonGroup->insert( ownerType, KACLListView::User ); + QRadioButton *owningGroupType =3D new QRadioButton( i18n("Owning Group= "), m_buttonGroup, "owningGroupType" ); + m_buttonGroup->insert( owningGroupType, KACLListView::Group ); + QRadioButton *othersType =3D new QRadioButton( i18n("Others"), m_butto= nGroup, "othersType" ); + m_buttonGroup->insert( othersType, KACLListView::Others ); + QRadioButton *maskType =3D new QRadioButton( i18n("Mask"), m_buttonGro= up, "maskType" ); + m_buttonGroup->insert( maskType, KACLListView::Mask ); + QRadioButton *namedUserType =3D new QRadioButton( i18n("Named User"), = m_buttonGroup, "namesUserType" ); + m_buttonGroup->insert( namedUserType, KACLListView::NamedUser ); + QRadioButton *namedGroupType =3D new QRadioButton( i18n("Named Group")= , m_buttonGroup, "namedGroupType" ); + m_buttonGroup->insert( namedGroupType, KACLListView::NamedGroup ); + + connect( m_buttonGroup, SIGNAL( clicked( int ) ), + this, SLOT( slotSelectionChanged( int ) ) ); + + m_widgetStack =3D new QWidgetStack( page ); + mainLayout->addWidget( m_widgetStack ); + + QHBox *usersBox =3D new QHBox( m_widgetStack ); + m_widgetStack->addWidget( usersBox, KACLListView::NamedUser ); + + QHBox *groupsBox =3D new QHBox( m_widgetStack ); + m_widgetStack->addWidget( groupsBox, KACLListView::NamedGroup ); + + QLabel *usersLabel =3D new QLabel( i18n( "User " ), usersBox ); + m_usersCombo =3D new QComboBox( false, usersBox, "users" ); + usersLabel->setBuddy( m_usersCombo ); + + QLabel *groupsLabel =3D new QLabel( i18n( "Group " ), groupsBox ); + m_groupsCombo =3D new QComboBox( false, groupsBox, "groups" ); + groupsLabel->setBuddy( m_groupsCombo ); + + if ( m_item ) { + m_buttonGroup->setButton( m_item->type ); + if ( m_defaultCB ) + m_defaultCB->setChecked( m_item->isDefault ); + slotUpdateAllowedTypes(); + slotSelectionChanged( m_item->type ); + slotUpdateAllowedUsersAndGroups(); + if ( m_item->type =3D=3D KACLListView::NamedUser ) { + m_usersCombo->setCurrentText( m_item->qualifier ); + } else if ( m_item->type =3D=3D KACLListView::NamedGroup ) { + m_groupsCombo->setCurrentText( m_item->qualifier ); + } + } else { + // new entry, preselect "named user", arguably the most common one + m_buttonGroup->setButton( KACLListView::NamedUser ); + slotUpdateAllowedTypes(); + slotSelectionChanged( KACLListView::NamedUser ); + slotUpdateAllowedUsersAndGroups(); + } + incInitialSize( QSize( 100, 0 ) ); +} + +void EditACLEntryDialog::slotUpdateAllowedTypes() +{ + int allowedTypes =3D m_allowedTypes; + if ( m_defaultCB && m_defaultCB->isChecked() ) { + allowedTypes =3D m_allowedDefaultTypes; + } + for ( int i=3D1; i < KACLListView::AllTypes; i=3Di*2 ) { + if ( allowedTypes & i ) + m_buttonGroup->find( i )->show(); + else + m_buttonGroup->find( i )->hide(); + } +} + +void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups() +{ + const QString oldUser =3D m_usersCombo->currentText(); + const QString oldGroup =3D m_groupsCombo->currentText(); + m_usersCombo->clear(); + m_groupsCombo->clear(); + if ( m_defaultCB && m_defaultCB->isChecked() ) { + m_usersCombo->insertStringList( m_defaultUsers ); + if ( m_defaultUsers.find( oldUser ) !=3D m_defaultUsers.end() ) + m_usersCombo->setCurrentText( oldUser ); + m_groupsCombo->insertStringList( m_defaultGroups ); + if ( m_defaultGroups.find( oldGroup ) !=3D m_defaultGroups.end() ) + m_groupsCombo->setCurrentText( oldGroup ); + } else { + m_usersCombo->insertStringList( m_users ); + if ( m_users.find( oldUser ) !=3D m_users.end() ) + m_usersCombo->setCurrentText( oldUser ); + m_groupsCombo->insertStringList( m_groups ); + if ( m_groups.find( oldGroup ) !=3D m_groups.end() ) + m_groupsCombo->setCurrentText( oldGroup ); + } +} +void EditACLEntryDialog::slotOk() +{ + KACLListView::EntryType type =3D static_cast(= m_buttonGroup->selectedId() ); + + QString qualifier; + if ( type =3D=3D KACLListView::NamedUser ) + qualifier =3D m_usersCombo->currentText(); + if ( type =3D=3D KACLListView::NamedGroup ) + qualifier =3D m_groupsCombo->currentText(); + + if ( !m_item ) { + m_item =3D new KACLListViewItem( m_listView, type, 0, false, quali= fier ); + } else { + m_item->type =3D type; + m_item->qualifier =3D qualifier; + } + if ( m_defaultCB ) + m_item->isDefault =3D m_defaultCB->isChecked(); + m_item->repaint(); + + KDialogBase::slotOk(); +} + +void EditACLEntryDialog::slotSelectionChanged( int id ) +{ + switch ( id ) { + case KACLListView::User: + case KACLListView::Group: + case KACLListView::Others: + case KACLListView::Mask: + m_widgetStack->setEnabled( false ); + break; + case KACLListView::NamedUser: + m_widgetStack->setEnabled( true ); + m_widgetStack->raiseWidget( KACLListView::NamedUser ); + break; + case KACLListView::NamedGroup: + m_widgetStack->setEnabled( true ); + m_widgetStack->raiseWidget( KACLListView::NamedGroup ); + break; + default: + break; + } +} + + +KACLListView::KACLListView( QWidget* parent, const char* name ) + : KListView( parent, name ), + m_hasMask( false ), m_allowDefaults( false ) +{ + // Add the columns + addColumn( i18n( "Type" ) ); + addColumn( i18n( "Name" ) ); + addColumn( i18n( "r" ) ); + addColumn( i18n( "w" ) ); + addColumn( i18n( "x" ) ); + addColumn( i18n( "Effective" ) ); + + header()->setClickEnabled( false ); + + // Load the avatars + if ( !QPixmapCache::find( s_itemAttributes[OWNER_IDX].pixmap ) ) { + for ( int i=3D0; i < LAST_IDX; i++ ) { + QPixmapCache::insert( s_itemAttributes[i].pixmap, + qembed_findImage( s_itemAttributes[i].pixmap ) ); + } + QPixmapCache::insert( "yes", qembed_findImage( "yes" ) ); + QPixmapCache::insert( "yespartial", qembed_findImage( "yespartial"= ) ); + } + + setSelectionMode( QListView::Extended ); + + // fill the lists of all legal users and groups + struct passwd *user =3D 0; + setpwent(); + while ( ( user =3D getpwent() ) !=3D 0 ) { + m_allUsers << QString::fromLatin1( user->pw_name ); + } + endpwent(); + + struct group *gr =3D 0; + setgrent(); + while ( ( gr =3D getgrent() ) !=3D 0 ) { + m_allGroups << QString::fromLatin1( gr->gr_name ); + } + endgrent(); + m_allUsers.sort(); + m_allGroups.sort(); +} + + +KACLListView::~KACLListView() +{ + +} + +QStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *a= llowedItem ) +{ + QStringList allowedUsers =3D m_allUsers; + QListViewItemIterator it( this ); + while ( it.current() ) { + const KACLListViewItem *item =3D static_cast( *it ); + ++it; + if ( !item->type =3D=3D NamedUser || item->isDefault !=3D defaults= ) continue; + if ( allowedItem && item =3D=3D allowedItem && allowedItem->isDefa= ult =3D=3D defaults ) continue; + allowedUsers.remove( item->qualifier ); + } + return allowedUsers; +} + +QStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *= allowedItem ) +{ + QStringList allowedGroups =3D m_allGroups; + QListViewItemIterator it( this ); + while ( it.current() ) { + const KACLListViewItem *item =3D static_cast( *it ); + ++it; + if ( !item->type =3D=3D NamedGroup || item->isDefault !=3D default= s ) continue; + if ( allowedItem && item =3D=3D allowedItem && allowedItem->isDefa= ult =3D=3D defaults ) continue; + allowedGroups.remove( item->qualifier ); + } + return allowedGroups; +} + +void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults ) +{ + // clear out old entries of that ilk + QListViewItemIterator it( this ); + while ( KACLListViewItem *item =3D static_cast( it.= current() ) ) { + ++it; + if ( item->isDefault =3D=3D defaults ) + delete item; + } + KACLListViewItem *item =3D + new KACLListViewItem( this, User, pACL.ownerPermissions(), default= s ); + + item =3D new KACLListViewItem( this, Group, pACL.owningGroupPermission= s(), defaults ); + + item =3D new KACLListViewItem( this, Others, pACL.othersPermissions(),= defaults ); + + bool hasMask =3D false; + unsigned short mask =3D pACL.maskPermissions( hasMask ); + if ( hasMask ) { + item =3D new KACLListViewItem( this, Mask, mask, defaults ); + } + + // read all named user entries + const ACLUserPermissionsList &userList =3D pACL.allUserPermissions(); + ACLUserPermissionsConstIterator itu =3D userList.begin(); + while ( itu !=3D userList.end() ) { + new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*= itu).first ); + ++itu; + } + + // and now all named groups + const ACLUserPermissionsList &groupList =3D pACL.allGroupPermissions(= ); + ACLUserPermissionsConstIterator itg =3D groupList.begin(); + while ( itg !=3D groupList.end() ) { + new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (= *itg).first ); + ++itg; + } +} + +void KACLListView::setACL( const KACL &acl ) +{ + if ( !acl.isValid() ) return; + // Remove any entries left over from displaying a previous ACL + m_ACL =3D acl; + fillItemsFromACL( m_ACL ); + + m_mask =3D acl.maskPermissions( m_hasMask ); + calculateEffectiveRights(); +} + +void KACLListView::setDefaultACL( const KACL &acl ) +{ + if ( !acl.isValid() ) return; + m_defaultACL =3D acl; + fillItemsFromACL( m_defaultACL, true ); + calculateEffectiveRights(); +} + +KACL KACLListView::itemsToACL( bool defaults ) const +{ + KACL newACL( 0 ); + bool atLeastOneEntry =3D false; + ACLUserPermissionsList users; + ACLGroupPermissionsList groups; + QListViewItemIterator it( const_cast( this ) ); + while ( QListViewItem* qlvi =3D it.current() ) { + ++it; + const KACLListViewItem* item =3D static_cast( q= lvi ); + if ( item->isDefault !=3D defaults ) continue; + atLeastOneEntry =3D true; + switch ( item->type ) { + case User: + newACL.setOwnerPermissions( item->value ); + break; + case Group: + newACL.setOwningGroupPermissions( item->value ); + break; + case Others: + newACL.setOthersPermissions( item->value ); + break; + case Mask: + newACL.setMaskPermissions( item->value ); + break; + case NamedUser: + users.append( qMakePair( item->text( 1 ), item->value ) ); + break; + case NamedGroup: + groups.append( qMakePair( item->text( 1 ), item->value ) ); + break; + default: + break; + } + } + if ( atLeastOneEntry ) { + newACL.setAllUserPermissions( users ); + newACL.setAllGroupPermissions( groups ); + if ( newACL.isValid() ) + return newACL; + } + return KACL(); +} + +KACL KACLListView::getACL() +{ + return itemsToACL( false ); +} + + +KACL KACLListView::getDefaultACL() +{ + return itemsToACL( true ); +} + +void KACLListView::contentsMousePressEvent( QMouseEvent * e ) +{ + QListViewItem *clickedItem =3D itemAt( contentsToViewport( e->pos() )= ); + if ( !clickedItem ) return; + // if the click is on an as yet unselected item, select it first + if ( !clickedItem->isSelected() ) + KListView::contentsMousePressEvent( e ); + + if ( !currentItem() ) return; + int column =3D header()->sectionAt( e->x() ); + acl_perm_t perm; + switch ( column ) + { + case 2: + perm =3D ACL_READ; + break; + case 3: + perm =3D ACL_WRITE; + break; + case 4: + perm =3D ACL_EXECUTE; + break; + default: + return KListView::contentsMousePressEvent( e ); + } + KACLListViewItem* referenceItem =3D static_cast( cl= ickedItem ); + unsigned short referenceHadItSet =3D referenceItem->value & perm; + QListViewItemIterator it( this ); + while ( KACLListViewItem* item =3D static_cast( it.= current() ) ) { + ++it; + if ( !item->isSelected() ) continue; + // toggle those with the same value as the clicked item, leave the= others + if ( referenceHadItSet =3D=3D ( item->value & perm ) ) + item->togglePerm( perm ); + } +} + +void KACLListView::entryClicked( QListViewItem* pItem, const QPoint& /*pt*= /, int col ) +{ + if ( !pItem ) return; + + QListViewItemIterator it( this ); + while ( KACLListViewItem* item =3D static_cast( it.= current() ) ) { + ++it; + if ( !item->isSelected() ) continue; + switch ( col ) + { + case 2: + item->togglePerm( ACL_READ ); + break; + case 3: + item->togglePerm( ACL_WRITE ); + break; + case 4: + item->togglePerm( ACL_EXECUTE ); + break; + + default: + ; // Do nothing + } + } + /* + // Has the user changed one of the required entries in a default ACL? + if ( m_pACL->aclType() =3D=3D ACL_TYPE_DEFAULT && + ( col =3D=3D 2 || col =3D=3D 3 || col =3D=3D 4 ) && + ( pACLItem->entryType() =3D=3D ACL_USER_OBJ || + pACLItem->entryType() =3D=3D ACL_GROUP_OBJ || + pACLItem->entryType() =3D=3D ACL_OTHER ) ) + { + // Mark the required entries as no longer being partial entries. + // That is, they will get applied to all selected directories. + KACLListViewItem* pUserObj =3D findACLEntryByType( this, ACL_USER_OBJ = ); + pUserObj->entry()->setPartialEntry( false ); + + KACLListViewItem* pGroupObj =3D findACLEntryByType( this, ACL_GROUP_OB= J ); + pGroupObj->entry()->setPartialEntry( false ); + + KACLListViewItem* pOther =3D findACLEntryByType( this, ACL_OTHER ); + pOther->entry()->setPartialEntry( false ); + + update(); + } + */ +} + + +void KACLListView::calculateEffectiveRights() +{ + QListViewItemIterator it( this ); + KACLListViewItem* pItem; + while ( ( pItem =3D dynamic_cast( it.current() ) ) = !=3D 0 ) + { + ++it; + pItem->calcEffectiveRights(); + } +} + + +unsigned short KACLListView::maskPermissions() const +{ + return m_mask; +} + + +void KACLListView::setMaskPermissions( unsigned short maskPerms ) +{ + m_mask =3D maskPerms; + calculateEffectiveRights(); +} + + +acl_perm_t KACLListView::maskPartialPermissions() const +{ + // return m_pMaskEntry->m_partialPerms; + return 0; +} + + +void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerm= s*/ ) +{ + //m_pMaskEntry->m_partialPerms =3D maskPartialPerms; + calculateEffectiveRights(); +} + +bool KACLListView::hasDefaultEntries() const +{ + QListViewItemIterator it( const_cast( this ) ); + while ( it.current() ) { + const KACLListViewItem *item =3D static_cast( it.current() ); + ++it; + if ( item->isDefault ) return true; + } + return false; +} + +const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType typ= e ) const +{ + return findItemByType( type, true ); +} + +const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool= defaults ) const +{ + QListViewItemIterator it( const_cast( this ) ); + while ( it.current() ) { + const KACLListViewItem *item =3D static_cast( it.current() ); + ++it; + if ( item->isDefault =3D=3D defaults && item->type =3D=3D type ) { + return item; + } + } + return 0; +} + + +unsigned short KACLListView::calculateMaskValue( bool defaults ) const +{ + // KACL auto-adds the relevant maks entries, so we can simply query + bool dummy; + return itemsToACL( defaults ).maskPermissions( dummy ); +} + +void KACLListView::slotAddEntry() +{ + int allowedTypes =3D NamedUser | NamedGroup; + if ( !m_hasMask ) + allowedTypes |=3D Mask; + int allowedDefaultTypes =3D NamedUser | NamedGroup; + if ( !findDefaultItemByType( Mask ) ) + allowedDefaultTypes |=3D Mask; + if ( !hasDefaultEntries() ) + allowedDefaultTypes |=3D User | Group; + EditACLEntryDialog dlg( this, 0, + allowedUsers( false ), allowedGroups( false ), + allowedUsers( true ), allowedGroups( true ), + allowedTypes, allowedDefaultTypes, m_allowDefa= ults ); + dlg.exec(); + KACLListViewItem *item =3D dlg.item(); + if ( !item ) return; // canceled + if ( item->type =3D=3D Mask && !item->isDefault ) { + m_hasMask =3D true; + m_mask =3D item->value; + } + if ( item->isDefault && !hasDefaultEntries() ) { + // first default entry, fill in what is needed + if ( item->type !=3D User ) { + unsigned short v =3D findDefaultItemByType( User )->value; + new KACLListViewItem( this, User, v, true ); + } + if ( item->type !=3D Group ) { + unsigned short v =3D findDefaultItemByType( Group )->value; + new KACLListViewItem( this, Group, v, true ); + } + if ( item->type !=3D Others ) { + unsigned short v =3D findDefaultItemByType( Others )->value; + new KACLListViewItem( this, Others, v, true ); + } + } + const KACLListViewItem *defaultMaskItem =3D findDefaultItemByType( Mas= k ); + if ( item->isDefault && !defaultMaskItem ) { + unsigned short v =3D calculateMaskValue( true ); + new KACLListViewItem( this, Mask, v, true ); + } + if ( !item->isDefault && !m_hasMask && + ( item->type =3D=3D Group + || item->type =3D=3D NamedUser + || item->type =3D=3D NamedGroup ) ) { + // auto-add a mask entry + unsigned short v =3D calculateMaskValue( false ); + new KACLListViewItem( this, Mask, v, false ); + } + calculateEffectiveRights(); + sort(); + setCurrentItem( item ); + // QListView doesn't seem to emit, in this case, and we need to update= =20 + // the buttons... + if ( childCount() =3D=3D 1 )=20 + emit currentChanged( item ); +} + +void KACLListView::slotEditEntry() +{ + QListViewItem * current =3D currentItem(); + if ( !current ) return; + KACLListViewItem *item =3D static_cast( current ); + int allowedTypes =3D item->type | NamedUser | NamedGroup; + bool itemWasMask =3D item->type =3D=3D Mask; + if ( !m_hasMask || itemWasMask ) + allowedTypes |=3D Mask; + int allowedDefaultTypes =3D item->type | NamedUser | NamedGroup; + if ( !findDefaultItemByType( Mask ) ) + allowedDefaultTypes |=3D Mask; + if ( !hasDefaultEntries() ) + allowedDefaultTypes |=3D User | Group; + + EditACLEntryDialog dlg( this, item, + allowedUsers( false, item ), allowedGroups( fa= lse, item ), + allowedUsers( true, item ), allowedGroups( tru= e, item ), + allowedTypes, allowedDefaultTypes, m_allowDefa= ults ); + dlg.exec(); + if ( itemWasMask && item->type !=3D Mask ) { + m_hasMask =3D false; + m_mask =3D 0; + } + if ( !itemWasMask && item->type =3D=3D Mask ) { + m_mask =3D item->value; + m_hasMask =3D true; + } + calculateEffectiveRights(); + sort(); +} + +void KACLListView::slotRemoveEntry() +{ + bool needsMask =3D findItemByType( NamedUser ) || findItemByType( Name= dGroup ); + bool needsDefaultMask =3D findDefaultItemByType( NamedUser ) || findDe= faultItemByType( NamedGroup ); + QListViewItemIterator it( this, QListViewItemIterator::Selected ); + while ( it.current() ) { + KACLListViewItem *item =3D static_cast( it.curr= ent() ); + ++it; + /* First check if it's a mask entry and if so, make sure that ther= e is + * either no name user or group entry, which means the mask can be= =20 + * removed, or don't remove it, but reset it. That is allowed. */ + if ( item->type =3D=3D Mask ) { + if ( !item->isDefault && !needsMask ) { + m_hasMask=3D false; + m_mask =3D 0; + delete item; + } else if ( item->isDefault && !needsDefaultMask ) { + delete item; + } else { + item->value =3D 0; + item->repaint(); + } + if ( !item->isDefault ) + calculateEffectiveRights(); + } else { + // for the base permissions, disable them, which is what libac= l does + if ( !item->isDefault && + ( item->type =3D=3D User + || item->type =3D=3D Group + || item->type =3D=3D Others ) ) { + item->value =3D 0; + item->repaint(); + } else { + delete item; + } + } + } +} + +#include "kacleditwidget.moc" +// vim:set ts=3D8 sw=3D4: Index: kfile/Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kfile/Makefile.am (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ kfile/Makefile.am (.../work/posix-acl-support/kdelibs/kio) (revision 44= 3749) @@ -39,7 +39,7 @@ include_HEADERS =3D kfiledialog.h kencodin =20 noinst_HEADERS =3D config-kfile.h krecentdirs.h kmetaprops.h \ kfilebookmarkhandler.h kfilemetainfowidget.h kopenwith_p.h \ =2D kfilespeedbar.h kpreviewprops.h + kfilespeedbar.h kpreviewprops.h kacleditwidget.h kacleditwidget_p.h image= s.h =20 libkfile_la_SOURCES =3D \ kfilefiltercombo.cpp \ @@ -56,7 +56,7 @@ libkfile_la_SOURCES =3D \ knotifydialog.cpp kfilespeedbar.cpp kpreviewwidgetbase.cpp \ kfilemetapreview.cpp kpropertiesdesktopbase.ui \ kpropertiesdesktopadvbase.ui kpropertiesmimetypebase.ui \ =2D kencodingfiledialog.cpp + kencodingfiledialog.cpp kacleditwidget.cpp =20 libkfile_la_COMPILE_FIRST =3D $(srcdir)/../kio/kdirnotify_stub.h =20 Index: tests/kacltest.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- tests/kacltest.h (.../KDE/3.5/kdelibs/kio) (revision 0) +++ tests/kacltest.h (.../work/posix-acl-support/kdelibs/kio) (revision 443= 749) @@ -0,0 +1,52 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Till Adam + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public Licen= se + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef KACLTEST_H +#define KACLTEST_H + +#include +#include + +class KACLTest +{ +public: + KACLTest(); + void setup(); + void runAll(); + void cleanup(); + + void testAsString(); + void testSetACL(); + void testGetOwnerPermissions(); + void testGetOwningGroupPermissions(); + void testGetOthersPermissions(); + void testGetMaskPermissions(); + void testGetAllUserPermissions(); + void testGetAllGroupsPermissions(); + void testIsExtended(); + void testOperators(); + void testSettingBasic(); + void testSettingExtended(); + void testSettingErrorHandling(); + +private: + KACL m_acl; +}; + +#endif Index: tests/kacltest.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- tests/kacltest.cpp (.../KDE/3.5/kdelibs/kio) (revision 0) +++ tests/kacltest.cpp (.../work/posix-acl-support/kdelibs/kio) (revision 4= 43749) @@ -0,0 +1,280 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Till Adam + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public Licen= se + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "kacltest.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +// The code comes partly from kdebase/kioslave/trash/testtrash.cpp + +static bool check(const QString& txt, QString a, QString b) +{ + if (a.isEmpty()) + a =3D QString::null; + if (b.isEmpty()) + b =3D QString::null; + if (a =3D=3D b) { + kdDebug() << txt << " : checking '" << a << "' against expected va= lue '" << b << "'... " << "ok" << endl; + } + else { + kdDebug() << txt << " : checking '" << a << "' against expected va= lue '" << b << "'... " << "KO !" << endl; + exit(1); + } + return true; +} + +template=20 +static bool check(const QString& txt, T a, T b) +{ + if (a =3D=3D b) { + kdDebug() << txt << " : checking '" << a << "' against expected va= lue '" << b << "'... " << "ok" << endl; + } + else { + kdDebug() << txt << " : checking '" << a << "' against expected va= lue '" << b << "'... " << "KO !" << endl; + exit(1); + } + return true; +} + +int main(int argc, char *argv[]) +{ + KApplication::disableAutoDcopRegistration(); + KCmdLineArgs::init(argc,argv,"kacltest", 0, 0, 0, 0); + KApplication app; + + KACLTest test; + test.setup(); + test.runAll(); + test.cleanup(); + kdDebug() << "All tests OK." << endl; + return 0; // success. The exit(1) in check() is what happens in case o= f failure. +} + +static const QString s_testACL( "user::rw-\nuser:bin:rwx\ngroup::rw-\nmask= ::rwx\nother::r--\n" ); +static const QString s_testACL2( "user::rwx\nuser:bin:rwx\ngroup::rw-\ngro= up:users:r--\ngroup:audio:--x\nmask::r-x\nother::r--\n" ); +static const QString s_testACLEffective("user::rwx\nuser:bin:rwx #effec= tive:r-x\ngroup::rw- #effective:r--\ngroup:audio:--x\ngroup:users:r--\= nmask::r-x\nother::r--\n"); + +KACLTest::KACLTest() +:m_acl( s_testACL ) +{ +} + +void KACLTest::setup() +{ +} + +void KACLTest::runAll() +{ + testAsString(); + testGetOwnerPermissions(); + testGetOwningGroupPermissions(); + testGetOthersPermissions(); + =20 + testGetMaskPermissions(); + testGetAllUserPermissions(); + + testIsExtended(); + + // from here on we operate with the second test string + testSetACL(); + testGetAllGroupsPermissions(); + + testOperators(); + testSettingBasic(); + testSettingExtended(); + testSettingErrorHandling(); +} + +void KACLTest::cleanup() +{ +} + +void KACLTest::testAsString() +{ + check( "asString: ", s_testACL, m_acl.asString() ); +} + +void KACLTest::testSetACL() +{ + m_acl.setACL( s_testACL2 ); + check( "setACL: ", s_testACLEffective.simplifyWhiteSpace(), m_acl.asStri= ng().simplifyWhiteSpace() ); +} + +void KACLTest::testGetOwnerPermissions() +{ + check( "Owner permissions: ", QString::number( m_acl.ownerPermissions() = ), "6" ); +} + +void KACLTest::testGetOwningGroupPermissions() +{ + check( "Owning group permissions: ", QString::number( m_acl.owningGroupP= ermissions() ), "6" ); +} + +void KACLTest::testGetOthersPermissions() +{ + check( "Others permissions: ", QString::number( m_acl.othersPermissions(= ) ), "4" ); +} + +void KACLTest::testGetMaskPermissions() +{ + bool exists =3D false; + unsigned short mask =3D m_acl.maskPermissions( exists ); + check( "Mask permissions: ", QString::number( mask ), "7" ); + check( "Mask permissions: ", exists, true ); +} + +void KACLTest::testGetAllUserPermissions() +{ + ACLUserPermissionsList list =3D m_acl.allUserPermissions(); + ACLUserPermissionsConstIterator it =3D list.begin(); + QString name; + unsigned short permissions; + int count =3D 0; + while ( it !=3D list.end() ) { + name =3D ( *it ).first; + permissions =3D ( *it ).second; + ++it; + ++count; + } + check( "All users count: ", QString::number( count ), "1" ); + check( "All users name: ", name, "bin" ); + check( "All users permissions: ", QString::number( permissions ), "7" ); +} + +void KACLTest::testGetAllGroupsPermissions() +{ + ACLGroupPermissionsList list =3D m_acl.allGroupPermissions(); + ACLGroupPermissionsConstIterator it =3D list.begin(); + QString name; + unsigned short permissions; + int count =3D 0; + while ( it !=3D list.end() ) { + name =3D ( *it ).first; + permissions =3D ( *it ).second; + // setACL sorts them alphabetically ... + if ( count =3D=3D 0 ) { + check( "All groups name: ", name, "audio" ); + check( "All groups permissions: ", QString::number( permissions ), "= 1" ); + } else if ( count =3D=3D 1 ) { + check( "All groups name: ", name, "users" ); + check( "All groups permissions: ", QString::number( permissions ), "= 4" ); + } + ++it; + ++count; + } + check( "All users count: ", QString::number( count ), "2" ); +} + +void KACLTest::testIsExtended() +{ + KACL dukeOfMonmoth( s_testACL ); + check( "isExtended on an extended one: ", dukeOfMonmoth.isExtended(), tr= ue ); + KACL earlOfUpnor( "user::r--\ngroup::r--\nother::r--\n" ); + check( "isExtended on a not extended one: ", earlOfUpnor.isExtended(), f= alse ); +} + +void KACLTest::testOperators() +{ + KACL dukeOfMonmoth( s_testACL ); + KACL JamesScott( s_testACL ); + KACL earlOfUpnor( s_testACL2 ); + check( "operator=3D=3D on different ones: ", dukeOfMonmoth =3D=3D earlOf= Upnor, false ); + check( "operator=3D=3D on identical ones: ", dukeOfMonmoth =3D=3D JamesS= cott, true ); + check( "operator!=3D on diffenrent ones: ", dukeOfMonmoth !=3D earlOfUpn= or, true ); + check( "operator!=3D: on identical ones: ", dukeOfMonmoth !=3D JamesScot= t, false ); +} + +void KACLTest::testSettingBasic() +{ + KACL CharlesII( s_testACL ); + CharlesII.setOwnerPermissions( 7 ); // clearly + CharlesII.setOwningGroupPermissions( 0 ); + CharlesII.setOthersPermissions( 0 ); + check( "setOwnerPermissions: ", QString::number( CharlesII.ownerPermissi= ons() ),"7" ); + check( "setOwningGroupPermissions: ", QString::number( CharlesII.owningG= roupPermissions() ),"0" ); + check( "setOthersPermissions: ", QString::number( CharlesII.othersPermis= sions() ),"0" ); +} + +void KACLTest::testSettingExtended() +{ + KACL CharlesII( s_testACL ); + CharlesII.setMaskPermissions( 7 ); // clearly + bool dummy =3D false; + check( "setMaskPermissions: ", QString::number( CharlesII.maskPermission= s( dummy ) ),"7" ); + + const QString expected( "user::rw-\nuser:root:rwx\nuser:bin:r--\ngroup::= rw-\nmask::rwx\nother::r--\n" ); + =20 + ACLUserPermissionsList users; + ACLUserPermissions user =3D qMakePair( QString( "root" ), ( unsigned sho= rt )7 ); + users.append( user ); + user =3D qMakePair( QString( "bin" ), ( unsigned short )4 ); + users.append( user ); + CharlesII.setAllUserPermissions( users ); + check( "setAllUserPermissions: ", CharlesII.asString(), expected ); + + CharlesII.setACL( s_testACL ); // reset + // it already has an entry for bin, let's change it + CharlesII.setNamedUserPermissions( QString("bin"), 4 ); + CharlesII.setNamedUserPermissions( QString( "root" ), 7 ); + check( "setNamedUserPermissions: ", CharlesII.asString(), expected ); + + // groups, all and named + =20 + const QString expected2( "user::rw-\nuser:bin:rwx\ngroup::rw-\ngroup:aud= io:-wx\ngroup:users:r--\nmask::rwx\nother::r--\n" ); + CharlesII.setACL( s_testACL ); // reset + ACLGroupPermissionsList groups; + ACLGroupPermissions group =3D qMakePair( QString( "audio" ), ( unsigned = short )3 ); + groups.append( group ); + group =3D qMakePair( QString( "users" ), ( unsigned short )4 ); + groups.append( group ); + CharlesII.setAllGroupPermissions( groups ); + check( "setAllGroupPermissions: ", CharlesII.asString(), expected2 ); + + CharlesII.setACL( s_testACL ); // reset + CharlesII.setNamedGroupPermissions( QString( "audio" ), 3 ); + CharlesII.setNamedGroupPermissions( QString( "users" ), 4 ); + check( "setNamedGroupPermissions: ", CharlesII.asString(), expected2 ); +} + +void KACLTest::testSettingErrorHandling() +{ + KACL foo( s_testACL ); + bool v =3D foo.setNamedGroupPermissions( "audio", 7 ); // existing group + check( "Existing group: ", v, true ); + v =3D foo.setNamedGroupPermissions( "jongel", 7 ); // non-existing group + check( "Non-existing group: ", v, false ); + + v =3D foo.setNamedUserPermissions( "bin", 7 ); // existing user + check( "Existing user: ", v, true ); + v =3D foo.setNamedUserPermissions( "jongel", 7 ); // non-existing user + check( "Non-existing user: ", v, false ); +} Index: tests/kioslavetest.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- tests/kioslavetest.cpp (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ tests/kioslavetest.cpp (.../work/posix-acl-support/kdelibs/kio) (revisi= on 443749) @@ -21,6 +21,7 @@ #include #include #include +#include #include =20 #include "kioslavetest.h" @@ -346,6 +347,16 @@ void KioslaveTest::slotSlaveError() slave =3D 0; } =20 +static void printACL( const QString& acl ) +{ + KACL kacl( acl ); + kdDebug() << "According to KACL: " << endl << kacl.asString() << endl; + kdDebug() << "Owner: " << kacl.ownerPermissions() << endl; + kdDebug() << "Owning group: " << kacl.owningGroupPermissions() << endl; + kdDebug() << "Others: " << kacl.othersPermissions() << endl; +} + + void KioslaveTest::printUDSEntry( const KIO::UDSEntry & entry ) { KIO::UDSEntry::ConstIterator it =3D entry.begin(); @@ -359,7 +370,19 @@ void KioslaveTest::printUDSEntry( const=20 } break; case KIO::UDS_ACCESS: =2D kdDebug() << "Access permissions : " << (mode_t)((*it).m= _long) << endl; + kdDebug() << "Access permissions : " << (*it).m_long << en= dl; + break; + case KIO::UDS_EXTENDED_ACL: + if( (*it).m_long =3D=3D 1 ) + kdDebug() << "Has extended ACL information." << endl; + break; + case KIO::UDS_ACL_STRING: + kdDebug() << "ACL: " << ( (*it).m_str.ascii() ) << endl; + printACL( (*it).m_str ); + break; + case KIO::UDS_DEFAULT_ACL_STRING: + kdDebug() << "Default ACL: " << ( (*it).m_str.ascii() ) <<= endl; + printACL( (*it).m_str ); break; case KIO::UDS_USER: kdDebug() << "User : " << ((*it).m_str.ascii() ) << endl; Index: tests/Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- tests/Makefile.am (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ tests/Makefile.am (.../work/posix-acl-support/kdelibs/kio) (revision 44= 3749) @@ -27,7 +27,7 @@ check_PROGRAMS =3D ksycocatest getalltest=20 previewtest kionetrctest kdcopcheck metatest \ kmimefromext kpropsdlgtest kmfitest dataprotocoltest \ kprotocolinfotest ksycocaupdatetest netaccesstest jobtest \ =2D kurlcompletiontest kmimetypetest + kurlcompletiontest kmimetypetest kacltest =20 # Unfortunately some tests depend on the network settings, it seems #check: kurifiltertest @@ -72,6 +72,7 @@ netaccesstest_SOURCES =3D netaccesstest.cp jobtest_SOURCES =3D jobtest.cpp kurlcompletiontest_SOURCES =3D kurlcompletiontest.cpp kmimetypetest_SOURCES =3D kmimetypetest.cpp +kacltest_SOURCES =3D kacltest.cpp =20 # kfile meta stuff. Comment this in, if you want a small # metadata plugin test and "make install". Index: Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- Makefile.am (.../KDE/3.5/kdelibs/kio) (revision 443749) +++ Makefile.am (.../work/posix-acl-support/kdelibs/kio) (revision 443749) @@ -32,7 +32,7 @@ libkio_la_LIBADD =3D kssl/libkssl.la kio/l kio/libksycoca.la bookmarks/libkbookmarks.la kfile/libkfile.la \ ../kdeui/libkdeui.la ../kdesu/libkdesu.la \ ../kwallet/client/libkwalletclient.la \ =2D $(LIBZ) $(LIBFAM) $(LIBVOLMGT) + $(LIBZ) $(LIBFAM) $(LIBVOLMGT) $(ACL_LIBS) =20 kde_mime_DATA =3D magic kde_servicetypes_DATA =3D application.desktop kurifilterplugin.desktop \ --Boundary-01=_Xrd9CIFan8zxw0w-- --nextPart1492079.yORxeDNXAC Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQBC9drctrsWGirveVsRAsU8AJ93a0P7il7365+zZxaNvGhsHJapBwCZAfRy uIZ+glFWQqgnCvDWC2zrGsY= =EVxe -----END PGP SIGNATURE----- --nextPart1492079.yORxeDNXAC--