D6829: Add ability to use the new kauth helper in file ioslave

David Faure noreply at phabricator.kde.org
Wed Aug 16 23:03:12 UTC 2017


dfaure requested changes to this revision.
dfaure added inline comments.
This revision now requires changes to proceed.

INLINE COMMENTS

> slavebase.cpp:1461
> +
> +PrivilegeOperationStatus SlaveBase::privilegeOperationStatus()
> +{

Oh, indeed, can't be const, because it's not a getter, it's a method that asks for the status via communication with the app.
That means the naming could be improved.

Maybe something like queryPrivilegeOperationStatus() or requestPrivilegeOperation().

> slavebase.cpp:1468
> +    KIO::PrivilegeOperationStatus currentOperationStatus;
> +    switch (buffer.toInt()) {
> +    case 1:

Not needed, just return KIO::PrivilegeOperationStatus(buffer.toInt())   (constructor-like syntax - or static_cast if that doesn't work).

If you think casting is evil, hardcoding 1/2/3 is even more evil ;-)

And in this case casting is not evil at all, we simply serialize/deserialize the enum using its integral value.

> slavebase.h:940
> +     * Checks with job if privilege operation is allowed.
> +     * @return one of the four status, OperationNotAllowed, OperationAllowed or OperationCanceled.
> +     * @see PrivilegeOperationStatus

Four? I count only three. No need to duplicate the full enum docu anyway, it's bound to go out-of-date at some point, just refer to the enum.

> file_unix.cpp:666
> +        if (opStatus == KIO::OperationCanceled) {
> +            mUserCanceled = true;
> +        }

No chance to return an enum instead of a bool here, to avoid modifying state?

The problem with mUserCanceled is that it's easy to get it wrong. Like in this patch, which never resets it to false for the next operation after one canceled operation. It's just cleaner to return an enum instead of modifying a member variable temporarily, although the question is, in both cases, what the caller code will look like...

My fear with a member var is that too many callers will forget to check it. 
Let's approach this from the viewpoint of the calling code.

Before:

  if (!dir.rmdir(itemPath)) {
      error(KIO::ERR_CANNOT_DELETE, itemPath);
      return false;
  }

After:

  if (!dir.rmdir(itemPath)) {
      if (auto ret = execWithElevatedPrivilege(RMDIR, itemPath)) { // for this to work, success must be 0 (or the returned type can be a class with operator bool()...)
          if (ret == KIO::OperationCanceled) { // or a different enum
              error(KIO::ERR_USER_CANCELED, itemPath);
          } else {
              error(KIO::ERR_CANNOT_DELETE, itemPath);
          }
          return false;
      }
  }

Alternatively, since we know cancelling will always need to error(KIO::ERR_USER_CANCELED) (and the QString argument doesn't matter), we could call error from within execWithElevatedPrivilege. But we still need the enum ret val:

  if (!dir.rmdir(itemPath)) {
      if (auto ret = execWithElevatedPrivilege(RMDIR, itemPath)) { // see above
          if (ret != KIO::OperationCanceled) { // or a different enum
              error(KIO::ERR_CANNOT_DELETE, itemPath);
          }
          return false;
      }
  }

I actually like the idea of returning a small class. Then it could even have a wasCanceled() method... we don't need an enum, we need a value that can convert to bool (for the if) and additionally let us know if cancelation happened. But all this in a temporary value, not in a member var of slavebase.

To flesh it out in more details:

  class ExecWithElevatedPrivilegeReturnValue
  {
  public:
      static ExecWithElevatedPrivilegeReturnValue success() { return ExecWithElevatedPrivilegeReturnValue{true, false}; }
      static ExecWithElevatedPrivilegeReturnValue failure() { return ExecWithElevatedPrivilegeReturnValue{true, false}; }
      static ExecWithElevatedPrivilegeReturnValue canceled() { return ExecWithElevatedPrivilegeReturnValue{true, true}; }
      operator bool() const { return m_success; }
      bool wasCanceled() const { return m_canceled; }
  private:
      ExecWithElevatedPrivilegeReturnValue(bool success, bool canceled) : m_success(success), m_canceled(canceled) {}
      const bool m_success;
      const bool m_canceled;
  };

(no setters, all of the slave code shouldn't be able to change this object, it's created immediately with the right values)

With this, the calling code can be simply

  if (!dir.rmdir(itemPath)) {
      if (auto ret = execWithElevatedPrivilege(RMDIR, itemPath)) {
          if (!ret.wasCanceled()) {
              error(KIO::ERR_CANNOT_DELETE, itemPath);
          }
          return false;
      }
  }

and the code in this review (execWithElevatedPrivilege) can do things like `return ExecWithElevatedPrivilegeReturnValue::canceled();` etc.

How does that sound?

REVISION DETAIL
  https://phabricator.kde.org/D6829

To: chinmoyr, dfaure, #frameworks
Cc: #frameworks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kde-frameworks-devel/attachments/20170816/4362ab60/attachment-0001.html>


More information about the Kde-frameworks-devel mailing list