-
Notifications
You must be signed in to change notification settings - Fork 806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refresh Windows download dialog progress when hydrating a placeholder #2981
Conversation
f34d8bd
to
3406895
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry... lacking time so only did a quick glance. There's clearly more things to deal with in there than what I had the time to point out.
@@ -44,6 +44,12 @@ struct OCSYNC_EXPORT VfsSetupParams | |||
*/ | |||
QString filesystemPath; | |||
|
|||
// Folder display name in Windows Explorer | |||
QString displayName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can get to that information (same thing for alias
) from FolderMan
by using the filesystemPath
. It's better to get fresh information straight from the Folder
object each time because they can change over time after that VfsSetupParams has been created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin I've been trying to avoid having a dependency to a FolderMan. We already have a dependency from GUI to VFS, so I thought two-way dependency is not a very good idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin One other thing is - I actually don't need a refreshed information about the alias. I am just using an alias to be able to set multiple sync folders for the same user. So it is used as the last part of syncRootId so each folder can have the same user account and Windows Sid, but different alias at the end (!0, !1, etc.). From what I have noticed - the alias is never changed. Unless the folder is removed and then another folder is added. Then the alias is reused. But, I am removing the Registry key for that folder that's being removed anyway. When unregistering the Registry key - I STILL need the same alias that I've used when registering it. Otherwise, the Registry key I am trying to unregister is noexisting.
src/gui/folderman.cpp
Outdated
@@ -76,6 +76,9 @@ FolderMan::FolderMan(QObject *parent) | |||
connect(AccountManager::instance(), &AccountManager::removeAccountFolders, | |||
this, &FolderMan::slotRemoveFoldersForAccount); | |||
|
|||
connect(AccountManager::instance(), &AccountManager::accountRemoved, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm I think this is emitted at application exit too... if I'm correct you don't want to call vfs->unregisterFolder()
there but only vfs->stop()
. Otherwise IIRC that would kill all the stored placeholder information in the folder every time you exit.
I think what you're after is about unregistering folders for accounts the user deleted? If yes how is that related to what this PR states? Just trying to connect the dots here. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm I think this is emitted at application exit too... if I'm correct you don't want to call
vfs->unregisterFolder()
there but onlyvfs->stop()
. Otherwise IIRC that would kill all the stored placeholder information in the folder every time you exit.I think what you're after is about unregistering folders for accounts the user deleted? If yes how is that related to what this PR states? Just trying to connect the dots here. :-)
@er-vin No. Absolutely no. I've been debugging it and it is not emitted. Only emitted when the account is removed.
Another question - when we are removing the account connection - why would we need to store placeholder information? My idea was - they are now invalid and we will instead register everything again when adding a new account connection (which actually happens now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin No. Absolutely no. I've been debugging it and it is not emitted. Only emitted when the account is removed.
This is surprising, I wonder if something else is broken because this is clearly emitted from AccountManager::shutdown()
which is called from the Application
dtor.
Another question - when we are removing the account connection - why would we need to store placeholder information? My idea was - they are now invalid and we will instead register everything again when adding a new account connection (which actually happens now).
Sure, when the user removes an account there's no need to keep placeholder information. My comment was more from the prospect of my first comment that I expect the folder removal code to be triggered on application exit which we wouldn't want. Placeholder information needs to stay put even if the application is exited.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Indeed, emit signal is there. But, the _folderMap
is empty by the time it gets emitted, that's why I am not hitting it. Anyways, thx for this comment, I definitely need to change this part to make it more reliable. Now, it works, just because _folderMap
is cleaned up in advance, but, it will break if something changes in the cleanup logic for _folderMap
.
@@ -35,6 +36,7 @@ Q_LOGGING_CATEGORY(lcCfApiWrapper, "nextcloud.sync.vfs.cfapi.wrapper", QtInfoMsg | |||
FIELD_SIZE( CF_OPERATION_PARAMETERS, field ) ) | |||
|
|||
namespace { | |||
QMap<QString, QString> registeredSyncRootKeys; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please no non-POD static. This is always asking for trouble and especially here because the code in this file tends to be reached by different threads!
Besides (I still need to read the rest of this PR) but I'm so far kind of surprised you need this at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Then, I need to convert this file into a class instead of just a namespace. I need to store registry paths that I've created so I can then remove them when I need to unregister a sync root. Another way - is to add parameters for "unregister" function, but, then, I will also need to change the interface for _vfs->unregister()
, just didn't want it to affect other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, no, you could go for Q_GLOBAL_STATIC (+ eventually a mutex to protect access if that's used on a code path from secondary thread, which in the context of that file would be anything called from one of the callbacks), it's having QMap straight as global static which will cause issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could go for Q_GLOBAL_STATIC (+ eventually a mutex to protect access
@er-vin Done. Hopefully, this is what you had in mind?
OCC::Result<void, QString> OCC::CfApiWrapper::registerSyncRoot(const QString &path, const QString &providerName, const QString &providerVersion, const QString &folderAlias, const QString &displayName, const QString &accountDisplayName) | ||
{ | ||
// even if we fail to register our sync root with shell, we can still proceed with using the VFS | ||
Q_ASSERT(createSyncRootRegistryKeys(providerName, folderAlias, displayName, accountDisplayName, path)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dangerous! This won't get executed in release builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dangerous! This won't get executed in release builds.
@er-vin In fact - I don't want it executed in Release builds. Why would I? I don't want the app to crash just because of non-working progress. But, now, I think, should I just keep the qcWarning() instead of assert in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point was that: createSyncRootRegistryKeys
won't even get called in release build. It's not just about asserting or not, the whole expression is compiled out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point was that:
createSyncRootRegistryKeys
won't even get called in release build. It's not just about asserting or not, the whole expression is compiled out.
@er-vin Indeed. Fixed.
{ | ||
Q_ASSERT(deleteSyncRootRegistryKey(path)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, won't be executed in release builds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin In fact, I don't need it executed in a release. But, maybe, I should just log a warning here instead? This code is not intended to crash and the app is planned to continue working even if it fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, won't be executed in release builds
@er-vin Fixed.
@@ -346,7 +467,7 @@ OCC::Result<OCC::CfApiWrapper::ConnectionKey, QString> OCC::CfApiWrapper::connec | |||
if (result != S_OK) { | |||
return QString::fromWCharArray(_com_error(result).ErrorMessage()); | |||
} else { | |||
return key; | |||
return std::move(key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dont use std::move on returns, it has no effect (I oversimplify a bit, it's often worse than that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dont use std::move on returns, it has no effect (I oversimplify a bit, it's often worse than that).
@er-vin Well, it gives a warning here every time I build the project. So, I decided to fix it. Now - there is no warning anymore, and the code still works. So, I guess - it's a win? :) Or, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, odd. Which warning is that? Sounds like a false positive. I seem to remember Visual Studio has kind of an old bug regarding this but I can't remember the specifics. Thing is that can prevent some return optimizations to use std::move on returns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, odd. Which warning is that? Sounds like a false positive. I seem to remember Visual Studio has kind of an old bug regarding this but I can't remember the specifics. Thing is that can prevent some return optimizations to use std::move on returns.
@er-vin This is coming from the Qt Creator:
cfapiwrapper.cpp:493:16: error: call to implicitly-deleted copy constructor of 'OCC::CfApiWrapper::ConnectionKey' cfapiwrapper.h:38:44: note: copy constructor of 'ConnectionKey' is implicitly deleted because field '_data' has a deleted copy constructor memory:2551:5: note: 'unique_ptr' has been explicitly marked deleted here result.h:34:14: note: passing argument to parameter 'value' here
It's because of std::unique_ptr<void, void(*)(void *)> _data;
within the class OWNCLOUDSYNC_EXPORT ConnectionKey
.
What I can also, alternatively is:
replace auto key = ConnectionKey();
with OCC::Result<OCC::CfApiWrapper::ConnectionKey, QString> key = ConnectionKey();
Then, std::move()
is not needed on key
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK. Got it now. This is because of the type elision. I think the better fix is: return { std::move(key) };
This should result in the same generated code but would avoid the confusion on read that the move is not being for what's returned. This is clearly what tripped me up here. :-)
src/libsync/vfs/cfapi/vfs_cfapi.cpp
Outdated
@@ -89,7 +89,7 @@ void VfsCfApi::stop() | |||
void VfsCfApi::unregisterFolder() | |||
{ | |||
const auto localPath = QDir::toNativeSeparators(params().filesystemPath); | |||
const auto result = cfapi::unegisterSyncRoot(localPath); | |||
const auto result = cfapi::unregisterSyncRoot(localPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
too bad this typo fix wasn't in a separate commit, that clouds a bit the review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Indeed? Well, I thought it is just so small so it doesn't deserve all the hassle with new PR + CI + merge? Anyways, can we let it slide just this time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No no, I just meant separate commit in this PR. When there's more than one commit I review each one separately which helps quite a lot.
But yes don't bother changing it now.
|
341482d
to
654b301
Compare
@er-vin One important question that blocks me from proceeding is - should I include Folderman into CfApiWrapper? The Folderman is in GUI, while the CfApiWrapper is in LibSync. The VFS is already included in the Folder, which is also GUI. Should I include them in both directions? Creating a double-connection? Or, maybe, it is better to keep passing the folder alias and folder display name via the VFS parameters when registering? And also, I am going to need to pass some parameters to Also, what about accountDisplayName? I need that value too for the Registry key. Should I also include AccountManager into the CfApiWrapper? I can as well pass the accountDisplayName into a register/unregister function as I do now (except for the unregister, I am going to need to add these parameters into the interface). |
Yes indeed, this is a problem.
I guess we'll have to roll with that for now although I'm slightly surprised so much is required now. We'll see when I get a chance to give it a proper review... dunno when...
Well, see my comment. I think my initial comment wasn't clear enough. ;-) |
bc1ed00
to
29d1f0e
Compare
src/gui/folderman.cpp
Outdated
@@ -76,6 +76,9 @@ FolderMan::FolderMan(QObject *parent) | |||
connect(AccountManager::instance(), &AccountManager::removeAccountFolders, | |||
this, &FolderMan::slotRemoveFoldersForAccount); | |||
|
|||
connect(AccountManager::instance(), &AccountManager::accountRemoved, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin No. Absolutely no. I've been debugging it and it is not emitted. Only emitted when the account is removed.
This is surprising, I wonder if something else is broken because this is clearly emitted from AccountManager::shutdown()
which is called from the Application
dtor.
Another question - when we are removing the account connection - why would we need to store placeholder information? My idea was - they are now invalid and we will instead register everything again when adding a new account connection (which actually happens now).
Sure, when the user removes an account there's no need to keep placeholder information. My comment was more from the prospect of my first comment that I expect the folder removal code to be triggered on application exit which we wouldn't want. Placeholder information needs to stay put even if the application is exited.
@@ -35,6 +38,9 @@ Q_LOGGING_CATEGORY(lcCfApiWrapper, "nextcloud.sync.vfs.cfapi.wrapper", QtInfoMsg | |||
FIELD_SIZE( CF_OPERATION_PARAMETERS, field ) ) | |||
|
|||
namespace { | |||
using SyncRootKeys = QMap<QString, QString>; | |||
Q_GLOBAL_STATIC(SyncRootKeys, registeredSyncRootKeys) | |||
QReadWriteLock registeredSyncRootKeysLock; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have so much contention on it that we need a read/write lock? It's much slower than a mutex in the general case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Fixed. Using a mutex now. But, I've got another idea. At the moment, we are always registering sync folders on application launch. Ideally, we shouldn't be doing this part if it is done already in the previous run, and we are not adding any new folders. So, I guess, I shouldn't really keep track of folders that I have added in the runtime, as, if we change this part in the future, I won't have information of registered folders if I restart the app. So, I guess, I need a way to traverse all the keys under *SyncRootManager* and check those that match by providername!WindowsSID!accountDisplayName and then just check if UserSyncRoots has a key that has a value of the sync root path we are removing. This will allow me to ditch this static map and also make the logic more reliable and less likely to becoe broken. Will just need to somehow pass the providerName and userDisplayName into unregister function, somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin I've removed that global static completely.
@@ -290,8 +301,134 @@ OCC::Optional<OCC::PinStateEnums::PinState> OCC::CfApiWrapper::PlaceHolderInfo:: | |||
return cfPinStateToPinState(_data->PinState); | |||
} | |||
|
|||
OCC::Result<void, QString> OCC::CfApiWrapper::registerSyncRoot(const QString &path, const QString &providerName, const QString &providerVersion) | |||
QString convertSidToStringSid(_In_ PSID sid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like code copied and pasted from an MSN example. :-)
Could we make that safer and more ergonomic using higher level constructs. I spent quite some time in the rest of that file to avoid construct like the stringSid raw pointer, the calls to LocalFree and so on. There's value in doing this, it pays off in safety and debug dividends. :-)
This apply to the whole block here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like code copied and pasted from an MSN example. :-)
Could we make that safer and more ergonomic using higher level constructs. I spent quite some time in the rest of that file to avoid construct like the stringSid raw pointer, the calls to LocalFree, and so on. There's value in doing this, it pays off in safety and debug dividends. :-)
This apply to the whole block here.
@er-vin I tried to get rid of ::LocalFree(stringSid); for like 1 hour. Tried different approaches. QScopedPointer with custom deleted. QVector<wchar_t>, using "delete[] stringSid" instead of ::LocalFree". Nothing worked. It either leads to a heap corruption assert and a crash, either empty SID string or, just doesn't compile. Kindly suggest your vision of how to replace this code with a Qt-like alternative.
Having said that, I don't think using WinAPI ::Local free with raw pointer is a problem inside the Windows-specific implementation source file. If we want to get rid of WinAPI, I guess, we shouldn't be using this ::ConvertSidToStringSid function at all. Not to mentioned, we shouldn't even be using CfAPI as Microsoft base all their constructs on WinAPI :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's not really about getting rid of WinAPI, this would be pointless. It's more that their documentation and examples tend to push to use dangerous constructs because well... they don't have better tooling available when you use just that API. But we do and so we shall try to move away from the more dangerous constructs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Alright. Well, I agree with you, but, I couldn't find any alternative to get rid of this construct. The problem here is, they expect a pointer to a pointer. So, they allocate memory and put it into that pointer internally. What I could do, is to try, and implement my own function convertSidToStringSid
by shifting required bits to obtain the string representation of WindowsSid. But, isn't it even worse? With their function, at least, we can expect the conversion to always work from one version of Windows to another. In the case of re-inventing the wheel, we will lose this reliability.
P.S. I can also move the function into "Utility" if this will improve the situation.
@@ -346,7 +467,7 @@ OCC::Result<OCC::CfApiWrapper::ConnectionKey, QString> OCC::CfApiWrapper::connec | |||
if (result != S_OK) { | |||
return QString::fromWCharArray(_com_error(result).ErrorMessage()); | |||
} else { | |||
return key; | |||
return std::move(key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK. Got it now. This is because of the type elision. I think the better fix is: return { std::move(key) };
This should result in the same generated code but would avoid the confusion on read that the move is not being for what's returned. This is clearly what tripped me up here. :-)
e2c2ef7
to
28e978b
Compare
28e978b
to
d2c84bc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, time's up, I'll get to the other functions another time. But at least that should give a direction for further adjustments.
LARGE_INTEGER progressCompleted; | ||
progressCompleted.QuadPart = offset; | ||
|
||
CfReportProviderProgress(callbackInfo->ConnectionKey, callbackInfo->TransferKey, callbackInfo->FileSize, progressCompleted); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say, please make a cfReportProviderProcess function akin to cfApiSendTransferInfo (or maybe move this into cfApiSendTransferInfo itself? but that'd force changing its interface a bit). Also I'd log CfReportProviderProgress failures just in case.
BTW, wouldn't you think they do that for you? I mean they know the total size (from the placeholder), the offset and the amount you just sent (provided in the CfExecute call)... but no, let's force people to mess with another piece of API just because. :-p
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Progress is not refreshed if not calling this function.
@@ -291,8 +297,147 @@ OCC::Optional<OCC::PinStateEnums::PinState> OCC::CfApiWrapper::PlaceHolderInfo:: | |||
return cfPinStateToPinState(_data->PinState); | |||
} | |||
|
|||
OCC::Result<void, QString> OCC::CfApiWrapper::registerSyncRoot(const QString &path, const QString &providerName, const QString &providerVersion) | |||
QString convertSidToStringSid(void *sid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used in retrieveWindowsSID only, so I'd either move it's content there or go the other way around completely and split a getTokenInformation out of retrieveWindowsSID. retriveWindowsSID would then become two simple calls.hink I think I prefer the latter actually. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Ok. It's the latter then.
OCC::Result<void, QString> OCC::CfApiWrapper::registerSyncRoot(const QString &path, const QString &providerName, const QString &providerVersion) | ||
QString convertSidToStringSid(void *sid) | ||
{ | ||
QString result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposal mostly removing some of the extra noise for readability IMHO:
wchar_t *stringSid = nullptr;
if (!ConvertSidToStringSid(sid, &stringSid)) {
return {};
}
const auto result = QString::fromWCharArray(stringSid);
LocalFree(stringSid);
return result;
QString retrieveWindowsSID() | ||
{ | ||
// FYI: code here is mostly identical to Windows-Classic-Examples/Samples/CloudMirror | ||
QScopedPointer<TOKEN_USER> tokenInfo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd favor std::unique_ptr these days. Less error prone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Ok. Bringing that back. I thought it makes no sense to create a method that returns a pointer of that token like it was done originally in that MS's sample. But, ok, let's bring back the old unique_ptr
returning function then.
|
||
const auto tokenHandle = GetCurrentThreadEffectiveToken(); | ||
|
||
DWORD tokenInfoSize = { 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd drop either the = or the curly braces, or move to auto tokenInfoSize = DWORD{0};
whichever suits you best.
|
||
DWORD tokenInfoSize = { 0 }; | ||
// first - get the required size | ||
if (!::GetTokenInformation(tokenHandle, TokenUser, nullptr, 0, &tokenInfoSize)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact this should always fail, otherwise we're in big trouble. :-)
I think I'd go for (man... I hate this API):
const auto tokenSizeCallSucceeded = GetTokenInformation(tokenHandle, TokenUser, nullptr, 0, &tokenInfoSize);
const auto lastError = GetLastError;
Q_ASSERT(!tokenSizeCallSucceeded && lastError == ERROR_INSUFFICIENT_BUFFER);
if (tokenSizeCallSucceeded || lastError != ERROR_INSUFFICIENT_BUFFER) {
// Log it
return {};
}
tokenInfo.reset(reinterpret_cast<TOKEN_USER*>(new char[tokenInfoSize]));
if (!GetTokenInformation(tokenHandle, TokenUser, tokenInfo.get(), tokenInfoSize, &tokenInfoSize)) {
// log it
return {};
}
return convertSidToStringSid(tokenInfo->User.Sid);
Something along those lines...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@er-vin Ok. Done.
4a95402
to
1ec93ed
Compare
@er-vin Pushed a commit with fixes. |
Oh I know, I was complaining at their API not at you. ;-)
I find stupid that they force people an extra bit of API while the other ones
have already all the information required...
|
Q_ASSERT(!tokenSizeCallSucceeded && lastError == ERROR_INSUFFICIENT_BUFFER); | ||
if (tokenSizeCallSucceeded || lastError != ERROR_INSUFFICIENT_BUFFER) { | ||
qCCritical(lcCfApiWrapper) << "GetTokenInformation for token size has failed with error" << lastError; | ||
return std::unique_ptr<TOKEN_USER>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: return {};
tokenInfo.reset(reinterpret_cast<TOKEN_USER*>(new char[tokenInfoSize])); | ||
if (!::GetTokenInformation(tokenHandle, TokenUser, tokenInfo.get(), tokenInfoSize, &tokenInfoSize)) { | ||
qCCritical(lcCfApiWrapper) << "GetTokenInformation failed with error" << lastError; | ||
return std::unique_ptr<TOKEN_USER>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
return convertSidToStringSid(tokenInfo->User.Sid); | ||
} | ||
|
||
return QString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto: return {};
return tokenInfo; | ||
} | ||
|
||
QString retrieveWindowsSID() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
retrieveWindowsSid
(instead of SID
mainly for consistency)
{ | ||
// We must set specific Registry keys to make the progress bar refresh correctly and also add status icons into Windows Explorer | ||
// More about this here: https://docs.microsoft.com/en-us/windows/win32/shell/integrate-cloud-storage | ||
const auto windowsSID = retrieveWindowsSID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/SID/Sid/g
const auto deleteKeyResult = OCC::Utility::registryDeleteKeyTree(HKEY_LOCAL_MACHINE, providerSyncRootIdRegistryKey); | ||
Q_ASSERT(!deleteKeyResult); | ||
} else { | ||
qCInfo(lcCfApiWrapper) << "Successfully set Registry keys for shell integration at:" << providerSyncRootIdRegistryKey << ". Progress bar will work."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be outside of the if, just after the loop and be followed by return true.
A couple less of states to track this way.
|
||
bool deleteSyncRootRegistryKey(const QString &syncRootPath, const QString &providerName, const QString &accountDisplayName) | ||
{ | ||
const auto &syncRootManagerRegistryKey = R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SyncRootManager\)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd drop the ref, this is an unwarranted indirection. You could wrap the raw string in QStringLiteral as well. AFAICT it gets implicitly converted to QString several times in the OCC::Utility calls.
const auto &syncRootManagerRegistryKey = R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SyncRootManager\)"; | ||
|
||
if (OCC::Utility::registryKeyExists(HKEY_LOCAL_MACHINE, syncRootManagerRegistryKey)) { | ||
const auto &windowsSID = retrieveWindowsSID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/SID/Sid/g
OCC::Utility::registryWalkSubKeys(HKEY_LOCAL_MACHINE, syncRootManagerRegistryKey, [&](HKEY, const QString &syncRootId) { | ||
// make sure we have matching syncRootId(providerName!windowsSID!accountDisplayName) | ||
if (syncRootId.startsWith(currentUserSyncRootIdPattern)) { | ||
const QString syncRootIdUserSyncRootsRegistryKey = syncRootManagerRegistryKey % syncRootId % R"(\UserSyncRoots\)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QStringLiteral and +
const QString syncRootIdUserSyncRootsRegistryKey = syncRootManagerRegistryKey % syncRootId % R"(\UserSyncRoots\)"; | ||
// check if there is a 'windowsSID' Registry value under \UserSyncRoots and it matches the sync folder path we are removing | ||
if (OCC::Utility::registryGetKeyValue(HKEY_LOCAL_MACHINE, syncRootIdUserSyncRootsRegistryKey, windowsSID).toString() == syncRootPath) { | ||
const QString syncRootIdToDelete = syncRootManagerRegistryKey % syncRootId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- but mainly for consistency
b3a1bb4
to
9ac54f1
Compare
562a71b
to
1a87bae
Compare
@er-vin Are we good? |
@er-vin Are we good?
Dunno, I had time to look only at half of it so far I think. I have to look at
it in chunk unfortunately. But we still have some time anyway, you aimed at
3.2.1 you said.
|
|
Well, I thought I've addressed your comments and could include this into RC.
As I said: dunno, didn't look at the last round yet + I commented only on what
I reviewed so far which was only part of it. I'm doing this on my free time
you know. :-)
|
Signed-off-by: allexzander <blackslayer4@gmail.com>
a4b23e6
to
193e503
Compare
AppImage file: Nextcloud-PR-2981-193e50311b94843e363d77350d28b60c3e4ae645-x86_64.AppImage |
@er-vin OK. Merged for now after fixing a bug that I've introduced when fixing the review comments :) It is always good to double-check. Confirmed as working. But, will gladly fix any other nitpicks you've got in a separate PR :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, in fact I was almost through. :-)
Just an issue with one of the latest adjustments.
qCCritical(lcCfApiWrapper) << "Couldn't send transfer info" << QString::number(transferKey.QuadPart, 16) << ":" << cfExecuteresult << QString::fromWCharArray(_com_error(cfExecuteresult).ErrorMessage()); | ||
} | ||
|
||
// refresh Windows Copy Dialog progress |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be conditional, if the status
passed in parameter is not STATUS_SUCCESS
there's no progress to report. This would happen on the server timing out during a download or such.
Documentation is here: https://docs.microsoft.com/en-us/windows/win32/shell/integrate-cloud-storage
Signed-off-by: allexzander blackslayer4@gmail.com